HTML / Javascript: comment accéder aux données JSON chargées dans une balise de script avec src set

90

J'ai ce fichier JSON que je génère sur le serveur que je souhaite rendre accessible sur le client car la page est visible. Fondamentalement, ce que je veux réaliser est:

J'ai la balise suivante déclarée dans mon document html:

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

Le fichier référencé dans sa source contient des données JSON. Comme je l'ai vu, les données ont été téléchargées, tout comme cela se produit avec les scripts.

Maintenant, comment y accéder en Javascript? J'ai essayé d'accéder à la balise de script, avec et sans jQuery, en utilisant une multitude de méthodes pour essayer d'obtenir mes données JSON, mais cela ne fonctionne pas. Le faire innerHTMLaurait fonctionné si les données json avaient été écrites en ligne dans le script. Ce que ce n'était pas et ce n'est pas ce que j'essaie de réaliser.

La requête JSON distante après le chargement de la page n'est pas non plus une option, au cas où vous voudriez le suggérer.

ChuckE
la source
3
Au lieu d'un fichier json, faites-en un fichier javascript qui affecte l'objet à une variable. L'autre approche consiste à utiliser ajax.
Asad Saeeduddin
3
La première suggestion est la mise en œuvre actuelle. Je ne voudrais pas le faire parce que j'utilise le comportement pour créer une structure. Je préférerais utiliser la structure pour la structure (si je veux JSON, j'obtiendrai JSON). La deuxième suggestion n'est pas souhaitée (j'ai besoin de ces données pour le processus d'initialisation).
ChuckE
1
@ChuckE via une <script>balise ou via AJAX, vous devrez toujours attendre qu'une requête HTTP supplémentaire se termine. Le navigateur ne vous permettra pas de lire le contenu du script si vous le récupérez avec un attribut "src", donc votre seule alternative est de faire une requête AJAX.
Pointy du
3
@Pointy via une balise <script>, les éléments seront évalués dès leur téléchargement. Si je place mon script json avant mon script js, les données du script json seront évaluées avant les données de script js, cela signifie que je ne vais pas attendre, les données sont déjà là. À propos de ma seule alternative, j'aimerais voir une documentation officielle avant d'être d'accord avec vous (ne pas dire que vous vous trompez, c'est exactement la raison pour laquelle j'ai écrit la question).
ChuckE
2
"La requête JSON distante après le chargement de la page n'est pas non plus une option, au cas où vous voudriez le suggérer." ... en quoi une requête JSON est-elle si différente d'une requête envoyée par un <script src=""></script>? Ils vont tous les deux faire des appels GET contre votre serveur.
Ben Lesh

Réponses:

114

Vous ne pouvez pas charger JSON comme ça, désolé.

Je sais que vous vous demandez "pourquoi je ne peux pas utiliser srcici? J'ai vu des trucs comme ça ...":

<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>

... pour le dire simplement, c'était juste la balise de script "abusée" en tant que détenteur de données. Vous pouvez le faire avec toutes sortes de données. Par exemple, de nombreux moteurs de création de modèles utilisent les balises de script pour contenir des modèles .

Vous avez une courte liste d'options pour charger votre JSON à partir d'un fichier distant:

  1. Utilisez $.get('your.json')ou une autre méthode AJAX.
  2. Ecrivez un fichier qui définit une variable globale dans votre json. (semble hokey).
  3. Tirez-le dans une iframe invisible, puis grattez le contenu de celui-ci après son chargement (j'appelle ce "mode 1997")
  4. Consultez un prêtre vaudou.

Dernier point:

La requête JSON distante après le chargement de la page n'est pas non plus une option, au cas où vous voudriez le suggérer.

... cela n'a pas de sens. La différence entre une requête AJAX et une requête envoyée par le navigateur lors du traitement de votre <script src="">n'est essentiellement rien. Ils feront tous les deux un GET sur la ressource. HTTP ne se soucie pas si c'est fait à cause d'une balise de script ou d'un appel AJAX, et votre serveur non plus.

Ben Lesh
la source
5
Très bonne réponse. Quand vous dites "la balise de script est" abusée ", vous voulez dire que c'est une mauvaise utilisation (peut-être pas mal, mais" créative ") de la balise de script? Votre n. L'option 2 est celle que nous avons déjà en production, je cherchais une solution strictement json / no-js, par pure expérimentation (je suis d'accord avec ce n'est pas possible si je suis sûr que c'est le cas). Concernant le dernier point, j'ai besoin de ces informations avant l'événement onload, et je ne veux pas que l'initialisation entière dépende d'une requête asynchrone qui peut varier dans le temps d'achèvement. C'est la principale différence entre l'appel Ajax et la balise de script.
ChuckE
1
Non, je ne pense pas que ce soit "faux", en soi, juste ... "créatif" est probablement un bon mot pour cela. Si réellement écrire le JSON dans la <script>balise est possible, j'irais dans cette voie, je suppose.
Ben Lesh
oui, tout le défi consistait à le charger en utilisant l'attribut src de la balise de script et à "masquer" ces informations dans le document.
ChuckE
Eh bien, vous ne pouvez pas vraiment masquer les données des utilisateurs dans une application de navigateur côté client. Ils peuvent simplement accéder aux outils de développement de leur navigateur et définir un point d'arrêt dans le JavaScript et examiner les objets comme ils le souhaitent.
Ben Lesh
1
@Jaydipsinh, vous devez alors résoudre vos problèmes CORS et utiliser Ajax. Il y a une raison pour laquelle les navigateurs interdisent ce type de comportement. La plupart des navigateurs ne vous permettront même plus de pirater CORS avec une iframe.
Ben Lesh
14

Une autre solution serait d'utiliser un langage de script côté serveur et d'inclure simplement json-data en ligne. Voici un exemple qui utilise PHP:

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

L'exemple ci-dessus utilise une balise de script supplémentaire avec type application/json. Une solution encore plus simple consiste à inclure le JSON directement dans le JavaScript:

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

L'avantage de la solution avec la balise supplémentaire est que le code JavaScript et les données JSON sont séparés les uns des autres.

Léa Rosema
la source
+ pour le contenu textuel. .html ne fonctionne pas pour moi sur la balise de script
Seth McClaine
9

Il semblerait que ce ne soit pas possible, ou du moins pas pris en charge.

À partir de la spécification HTML5 :

Lorsqu'il est utilisé pour inclure des blocs de données (par opposition aux scripts), les données doivent être incorporées en ligne , le format des données doit être donné à l'aide de l'attribut type, l'attribut src ne doit pas être spécifié et le contenu de l'élément de script doit être conforme aux exigences définies pour le format utilisé.

btx9000
la source
1
Semble être une politique pour traiter les données comme plus sensibles que JS et CSS.
5

Bien que ce ne soit actuellement pas possible avec la scriptbalise, cela est possible avec un iframesi elle provient du même domaine.

<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>

Pour utiliser ce qui précède, remplacez simplement l' attribut idet srcpar ce dont vous avez besoin. Le id(que nous supposerons dans cette situation est égal à mySpecialId) sera utilisé pour stocker les données dans window.jsonData["mySpecialId"].

En d'autres termes, pour chaque iframe qui a un idet utilise le onloadscript aura ces données chargées de manière synchrone dans l' window.jsonDataobjet sous le id.

Je l' ai fait pour le plaisir et pour montrer qu'il est « possible » , mais je ne pas recommander qu'il soit utilisé.


Voici une alternative qui utilise un rappel à la place.

<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>

Testé dans Chrome et devrait fonctionner dans Firefox. Incertain à propos d'IE ou de Safari.

fantôme de kemicofa
la source
3

Je suis d'accord avec Ben. Vous ne pouvez pas charger / importer le fichier JSON simple.

Mais si vous voulez absolument faire cela et avoir la flexibilité de mettre à jour le fichier json, vous pouvez

mon-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>
Karan
la source
2

Vérifiez cette réponse: https://stackoverflow.com/a/7346598/1764509

$.getJSON("test.json", function(json) {
    console.log(json); // this will show the info it in firebug console
});
L.Grillo
la source
3
$ .getJSON () est un appel ajax.
Tobi G.
Comment puis-je afficher les informations dans un fichier HTML lié au lieu de la console?
T.Doe
2

Si vous devez charger JSON depuis un autre domaine: http://en.wikipedia.org/wiki/JSONP
Cependant, soyez conscient des attaques XSSI potentielles: https://www.scip.ch/en/?labs.20160414

Si c'est le même domaine, utilisez simplement Ajax.

Vitaliy Kaplich
la source
2
JSONP ne fonctionne pas avec les résultats au format JSON. De plus, les paramètres JSONP passés en arguments à un script sont définis par le serveur… auquel vous n'avez peut-être pas accès.
e-sushi
1

placez quelque chose comme ça dans votre fichier de script json-content.js

var mainjson = { your json data}

puis appelez-le depuis la balise de script

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

alors vous pouvez l'utiliser dans le prochain script

<script>
console.log(mainjson)
</script>
hossein sedighian
la source
0

Une autre alternative pour utiliser le json exact dans javascript. Comme il s'agit de notation d'objets Javascript, vous pouvez simplement créer votre objet directement avec la notation json. Si vous stockez cela dans un fichier .js, vous pouvez utiliser l'objet dans votre application. C'était une option utile pour moi lorsque j'avais des données json statiques que je voulais mettre en cache dans un fichier séparément du reste de mon application.

    //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
            }
        ]
    };
DominicTurner
la source