HTML / Javascript: як отримати доступ до даних JSON, завантажених у тег сценарію з набором src


90

У мене є цей файл JSON, який я створюю на сервері, який я хочу зробити доступним для клієнта, оскільки сторінку можна переглянути. В основному я хочу досягти:

У моєму HTML-документі оголошено такий тег:

<script id="test" type="application/json" src="http://myresources/stuf.json">

Файл, згаданий у своєму джерелі, має дані JSON. Як я вже бачив, дані завантажено, як це відбувається зі сценаріями.

Тепер, як отримати доступ до нього у Javascript? Я намагався отримати доступ до тегу сценарію, з jQuery і без нього, використовуючи безліч методів, щоб спробувати отримати свої дані JSON, але якось це не працює. Отримання його innerHTMLспрацювало б, якби дані json були вписані в сценарій вбудовано. Що це не було і не те, що я намагаюся досягти.

Віддалений запит JSON після завантаження сторінки також не є можливим, якщо ви хочете це запропонувати.


3
Замість файлу json зробіть його файлом javascript, який призначає об’єкт змінній. Інший підхід - використання ajax.
Асад Саедуддін

3
Перша пропозиція - це поточна реалізація. Я б не хотів цього робити, оскільки використовую поведінку для доставки структури. Я вважаю за краще використовувати структуру для структури (якщо я хочу JSON, я отримаю JSON). Друга пропозиція не потрібна (мені потрібні ці дані для процесу ініціалізації).
ChuckE

1
@ChuckE через <script>тег або через AJAX вам все одно доведеться чекати завершення додаткового запиту HTTP. Браузер не дозволяє читати вміст сценарію, якщо ви отримуєте його з атрибутом "src", тому ваша єдина альтернатива - зробити запит AJAX.
Пойнті

3
@Pointy через тег <script> буде оцінено, як тільки буде завантажено. Якщо я розміщу скрипт json перед сценарієм js, дані сценарію json будуть оцінені перед даними сценарію js, це означає, що я не збираюся чекати, дані вже є. Про те, що це моя єдина альтернатива, я хотів би переглянути офіційну документацію, перш ніж погодитись з вами (не кажучи, що ви помиляєтеся, якраз саме тому я і написав запитання).
ChuckE

2
"Віддалений запит JSON після завантаження сторінки також не є можливим, якщо ви хочете це запропонувати." ... чим запит JSON так сильно відрізняється від запиту, надісланого <script src=""></script>? Вони обидва будуть робити дзвінки GET на ваш сервер.
Ben Lesh

Відповіді:


114

Ви не можете завантажити JSON так, вибачте.

Я знаю, ти думаєш: "чому я не можу просто srcтут скористатися ? Я бачив подібні речі ...":

<script id="myJson" type="application/json">
 { 
   name: 'Foo' 
 }
</script>

<script type="text/javascript">
    $(function() {
        var x = JSON.parse($('#myJson').html());
        alert(x.name); //Foo
     });
</script>

... ну простіше кажучи, це був просто тег скрипта, яким «зловживали» як власника даних. Ви можете зробити це за допомогою різноманітних даних. Наприклад, багато механізмів шаблонування використовують теги скриптів для зберігання шаблонів .

У вас є короткий список варіантів завантаження JSON із віддаленого файлу:

  1. Використовуйте $.get('your.json') або будь-який інший такий метод AJAX.
  2. Напишіть файл, який встановлює глобальну змінну для вашого json. (здається хокей).
  3. Витягніть його в невидимий iframe, а потім зішкребіть вміст після завантаження (я називаю це "режимом 1997")
  4. Зверніться до священика вуду.

Кінцева точка:

Віддалений запит JSON після завантаження сторінки також не є можливим, якщо ви хочете це запропонувати.

... це не має сенсу. Різниця між запитом AJAX та запитом, надісланим браузером під час обробки вашого <script src="">, по суті, ніщо. Вони обидва будуть робити GET на ресурсі. HTTP не має значення, чи це зроблено через тег сценарію або виклик AJAX, а також ваш сервер.


5
Чудова відповідь. Коли ви говорите "тег сценарію" зловживають ", ви маєте на увазі неправильне (можливо, не неправильне, але" творче ") використання тегу сценарію? Ваш н. 2 варіант - це той, який ми вже маємо у виробництві, я шукав суто рішення json / no-js, з чистого експериментування (я чудово розумію, що це неможливо, якщо я впевнений, що воно є). Щодо остаточного пункту, мені потрібна ця інформація перед подією onload, і я не хочу, щоб вся ініціалізація залежала від асинхронного запиту, який може змінюватися за часом завершення. Це ключова різниця між викликом Ajax і тегом сценарію.
ChuckE

1
Ні, я не думаю, що це "неправильно", скажімо, просто ... "креатив" - це, мабуть, гарне слово для цього. Якщо насправді ввести JSON у <script>тег можливо, я б пішов цим шляхом, мабуть.
Бен Леш,

так, вся проблема полягала в завантаженні його за допомогою атрибута тегу скрипта src та "заплутування" цієї інформації в документі.
ChuckE

Ну, ви не можете насправді приховати дані від користувачів у програмі браузера на стороні клієнта. Вони можуть просто зайти в інструменти розробника свого браузера і встановити точку зупинки в JavaScript і досліджувати об’єкти, як їм подобається.
Бен Леш,

1
@Jaydipsinh, то вам потрібно вирішити свої проблеми з CORS та скористатися Ajax. Існує причина, через яку браузери забороняють подібну поведінку. Більшість браузерів більше навіть не дозволяють вам прокручувати CORS за допомогою iframe.
Ben Lesh

14

Іншим рішенням було б використання мови сценаріїв на стороні сервера і просто включення вбудованих даних json. Ось приклад, який використовує PHP:

<script id="data" type="application/json"><?php include('stuff.json'); ?></script>
<script>
var jsonData = JSON.parse(document.getElementById('data').textContent)
</script>

У наведеному вище прикладі використовується додатковий тег сценарію з типом application/json. Ще простішим рішенням є включення JSON безпосередньо в JavaScript:

<script>var jsonData = <?php include('stuff.json');?>;</script>

Перевагою рішення з додатковим тегом є те, що код JavaScript та дані JSON зберігаються окремо один від одного.


+ для змісту тексту. .html у мене не працює на тезі сценарію
Сет Макклейн,

9

Здається, це неможливо або, принаймні, не підтримується.

З специфікації HTML5 :

При використанні для включення блоків даних (на відміну від сценаріїв) дані повинні бути вбудовані вбудовано , формат даних повинен бути вказаний за допомогою атрибута type, атрибут src не повинен бути вказаний , а вміст елемента script повинен відповідати до вимог, визначених для використовуваного формату.


1
Здається, це політика щодо обробки даних як більш чутливих, ніж JS та CSS.

5

Хоча в даний час це неможливо з scriptтегом, це можливо, iframeякщо це з того самого домену.

<iframe
id="mySpecialId"
src="/my/link/to/some.json"
onload="(()=>{if(!window.jsonData){window.jsonData={}}try{window.jsonData[this.id]=JSON.parse(this.contentWindow.document.body.textContent.trim())}catch(e){console.warn(e)}this.remove();})();"
onerror="((err)=>console.warn(err))();"
style="display: none;"
></iframe>

Щоб скористатися вищезазначеним, просто замініть атрибут idand srcтим, що вам потрібно. Значення id(яке ми припустимо в цій ситуації дорівнює mySpecialId) буде використано для зберігання даних у window.jsonData["mySpecialId"].

Іншими словами, для кожного iframe, який має сценарій idта використовує onloadскрипт, дані будуть синхронно завантажені в window.jsonDataоб'єкт під idзазначеним.

Я зробив це для розваги та для того, щоб показати, що це "можливо", але я не рекомендую використовувати це.


Ось альтернатива, яка замість цього використовує зворотний дзвінок.

<script>
    function someCallback(data){
        /** do something with data */
        console.log(data);

    }
    function jsonOnLoad(callback){
        const raw = this.contentWindow.document.body.textContent.trim();
        try {
          const data = JSON.parse(raw);
          /** do something with data */
          callback(data);
        }catch(e){
          console.warn(e.message);
        }
        this.remove();
    }
</script>
<!-- I frame with src pointing to json file on server, onload we apply "this" to have the iframe context, display none as we don't want to show the iframe -->
<iframe src="your/link/to/some.json" onload="jsonOnLoad.apply(this, someCallback)" style="display: none;"></iframe>

Перевірений на хром і повинен працювати у firefox. Не впевнені щодо IE або Safari.


3

Я згоден з Беном. Ви не можете завантажити / імпортувати простий файл JSON.

Але якщо ви абсолютно хочете це зробити і маєте гнучкість для оновлення файлу json, ви можете

my-json.js

   var myJSON = {
      id: "12ws",
      name: "smith"
    }

index.html

<head>
  <script src="my-json.js"></script>
</head>
<body onload="document.getElementById('json-holder').innerHTML = JSON.stringify(myJSON);">
  <div id="json-holder"></div>
</body>


2

Якщо вам потрібно завантажити JSON з іншого домену: http://en.wikipedia.org/wiki/JSONP
Однак майте на увазі потенційні атаки XSSI: https://www.scip.ch/en/?labs.20160414

Якщо це той самий домен, просто використовуйте Ajax.


2
JSONP не працює з результатами форматування JSON. Крім того, параметри JSONP, передані як аргументи скрипту, визначаються сервером ..., до якого ви можете не мати доступу.
е-суші

1

помістіть щось подібне до вашого файлу сценарію json-content.js

var mainjson = { your json data}

потім викличте його з тегу скрипта

<script src="json-content.js"></script>

тоді ви можете використовувати його в наступному сценарії

<script>
console.log(mainjson)
</script>

0

Ще одна альтернатива використанню точного json у javascript. Оскільки це нотація об'єктів Javascript, ви можете просто створити свій об'єкт безпосередньо за допомогою нотації json. Якщо ви зберігаєте це у файлі .js, ви можете використовувати об'єкт у своїй програмі. Це було корисною опцією для мене, коли у мене були деякі статичні дані json, які я хотів кешувати у файлі окремо від решти мого додатка.

    //Just hard code json directly within JS
    //here I create an object CLC that represents the json!
    $scope.CLC = {
        "ContentLayouts": [
            {
                "ContentLayoutID": 1,
                "ContentLayoutTitle": "Right",
                "ContentLayoutImageUrl": "/Wasabi/Common/gfx/layout/right.png",
                "ContentLayoutIndex": 0,
                "IsDefault": true
            },
            {
                "ContentLayoutID": 2,
                "ContentLayoutTitle": "Bottom",
                "ContentLayoutImageUrl": "/Wasabi/Common/gfx/layout/bottom.png",
                "ContentLayoutIndex": 1,
                "IsDefault": false
            },
            {
                "ContentLayoutID": 3,
                "ContentLayoutTitle": "Top",
                "ContentLayoutImageUrl": "/Wasabi/Common/gfx/layout/top.png",
                "ContentLayoutIndex": 2,
                "IsDefault": false
            }
        ]
    };
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.