HTML / Javascript: как получить доступ к данным JSON, загруженным в тег скрипта с установленным src


91

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

В моем html-документе объявлен следующий тег:

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

Файл, указанный в его источнике, содержит данные JSON. Как я видел, данные были загружены, как и в случае со скриптами.

Теперь, как мне получить к нему доступ в Javascript? Я пробовал получить доступ к тегу скрипта с jQuery и без него, используя множество методов, чтобы попытаться получить мои данные JSON, но почему-то это не работает. Получение его innerHTMLсработало бы, если бы данные json были встроены в сценарий. Этого не было и не то, чего я пытаюсь достичь.

Удаленный запрос JSON после загрузки страницы также не подходит, если вы хотите это предложить.


3
Вместо файла json сделайте его файлом javascript, который присваивает объект переменной. Другой подход - использовать ajax.
Asad Saeeduddin

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

1
@ChuckE через <script>тег или AJAX, вам все равно придется ждать завершения дополнительного HTTP-запроса. Браузер не позволит вам прочитать содержимое скрипта, если вы получите его с атрибутом «src», поэтому единственная альтернатива - сделать запрос AJAX.
Pointy

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

2
«Удаленный запрос JSON после загрузки страницы также не подходит, если вы хотите это предложить». ... чем запрос JSON так сильно отличается от запроса, отправленного a <script src=""></script>? Они оба будут выполнять вызовы GET против вашего сервера.
Бен Леш

Ответы:


116

Вы не можете загрузить такой 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
Отличный ответ. Когда вы говорите «злоупотребление тегом сценария», вы имеете в виду, что это неправильное (может быть, не неправильное, но «творческое») использование тега сценария? Ваш n. 2 - это тот, который у нас уже есть в производстве, я искал строго json / no-js решение из чистого эксперимента (меня устраивает, что это невозможно, если я уверен, что это так). Что касается последнего пункта, мне нужна эта информация перед событием onload, и я не хочу, чтобы вся инициализация зависела от асинхронного запроса, время выполнения которого может меняться. Это ключевое различие между вызовом Ajax и тегом скрипта.
ChuckE

1
Нет, я не думаю, что это «неправильно», просто ... «творческий», вероятно, подходящее слово для этого. Если на самом деле запись JSON в <script>тег возможна, я бы пошел по этому пути.
Бен Леш

да, вся проблема заключалась в том, чтобы загрузить его с помощью атрибута src тега скрипта и «скрыть» эту информацию в документе.
ChuckE

Что ж, вы не можете скрыть данные от пользователей в клиентском приложении браузера. Они могут просто зайти в инструменты разработчика своего браузера, установить точку останова в JavaScript и исследовать объекты, как им нравится.
Бен Леш

1
@Jaydipsinh, тогда вам нужно решить проблемы с CORS и использовать Ajax. Браузеры не зря запрещают подобное поведение. Большинство браузеров больше не позволяют вам даже взломать CORS с помощью iframe.
Бен Леш

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 не должен быть указан , а содержимое элемента сценария должно соответствовать требованиям, определенным для используемого формата.


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>

Для использования выше, просто заменить idи 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, вы можете

мой-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, передаваемые в качестве аргументов сценарию, определяются сервером… к которому у вас может не быть доступа.
e-sushi

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.