HTML / Javascript: cómo acceder a los datos JSON cargados en una etiqueta de script con src set


90

Tengo este archivo JSON que genero en el servidor que quiero hacer accesible en el cliente ya que la página es visible. Básicamente lo que quiero lograr es:

Tengo la siguiente etiqueta declarada en mi documento html:

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

El archivo referido en su fuente tiene datos JSON. Como he visto, se han descargado datos, al igual que ocurre con los scripts.

Ahora, ¿cómo accedo a él en Javascript? Intenté acceder a la etiqueta de script, con y sin jQuery, usando una multitud de métodos para intentar obtener mis datos JSON, pero de alguna manera esto no funciona. Obtenerlo innerHTMLhabría funcionado si los datos json se hubieran escrito en línea en el script. Lo cual no fue ni es lo que estoy tratando de lograr.

La solicitud JSON remota después de que se cargue la página tampoco es una opción, en caso de que quiera sugerirlo.


3
En lugar de un archivo json, conviértalo en un archivo javascript que asigne el objeto a una variable. El otro enfoque es usar ajax.
Asad Saeeduddin

3
La primera sugerencia es la implementación actual. Me gustaría no hacerlo porque estoy usando el comportamiento para entregar estructura. Preferiría usar estructura por estructura (si quiero JSON, obtendré JSON). No se desea una segunda sugerencia (necesito estos datos para el proceso de inicialización).
ChuckE

1
@ChuckE a través de una <script>etiqueta o mediante AJAX, todavía tendrá que esperar a que se complete una solicitud HTTP adicional. El navegador no le permitirá leer el contenido del script si lo busca con un atributo "src", por lo que su única alternativa es realizar una solicitud AJAX.
Puntiagudo

3
@Pointy a través de una etiqueta <script>, el material se evaluará tan pronto como se descargue. Si coloco mi script json antes de mi script js, los datos del script json se evaluarán antes que los datos del script js, eso significa que no voy a esperar, los datos ya están allí. Acerca de que es mi única alternativa, me gustaría ver alguna documentación oficial antes de estar de acuerdo con usted (no digo que esté equivocado, solo esa fue exactamente la razón por la que escribí la pregunta).
ChuckE

2
"La solicitud remota de JSON después de la carga de la página tampoco es una opción, en caso de que quiera sugerir eso". ... ¿en qué se diferencia una solicitud JSON de una solicitud enviada por un <script src=""></script>? Ambos harán llamadas GET contra su servidor.
Ben Lesh

Respuestas:


114

No puedes cargar JSON así, lo siento.

Sé que estás pensando "¿por qué no puedo usarlo srcaquí? He visto cosas como esta ...":

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

... bueno, para decirlo de manera simple, eso fue solo la etiqueta de script siendo "abusada" como un contenedor de datos. Puede hacerlo con todo tipo de datos. Por ejemplo, muchos motores de creación de plantillas aprovechan las etiquetas de script para contener plantillas .

Tiene una breve lista de opciones para cargar su JSON desde un archivo remoto:

  1. Utilice $.get('your.json')o algún otro método AJAX similar.
  2. Escriba un archivo que establezca una variable global para su json. (parece cursi).
  3. Colóquelo en un iframe invisible, luego raspe el contenido de eso después de que se cargue (llamo a esto "modo 1997")
  4. Consulta con un sacerdote vudú.

Punto final:

La solicitud JSON remota después de que se cargue la página tampoco es una opción, en caso de que quiera sugerirlo.

... eso no tiene sentido. La diferencia entre una solicitud AJAX y una solicitud enviada por el navegador mientras procesa su <script src="">es esencialmente nada. Ambos harán un GET en el recurso. A HTTP no le importa si se hace debido a una etiqueta de script o una llamada AJAX, y tampoco a su servidor.


5
Gran respuesta. Cuando dice "la etiqueta de secuencia de comandos está 'abusada'", ¿quiere decir que es un uso incorrecto (tal vez no incorrecto, pero "creativo") de la etiqueta de secuencia de comandos? Tu n. La opción 2 es la que ya tenemos en producción, estaba buscando una solución estrictamente json / no-js, por pura experimentación (estoy bien con que no sea posible si estoy seguro de que lo es). Con respecto al punto final, necesito esta información antes del evento de carga y no quiero que toda la inicialización dependa de una solicitud asincrónica que puede variar en el tiempo de finalización. Esta es la diferencia clave entre la llamada Ajax y la etiqueta de script.
ChuckE

1
No, no creo que esté "mal", por decir, solo ... "creativo" es probablemente una buena palabra para describirlo. Si realmente <script>es posible escribir el JSON en la etiqueta, supongo que seguiría esa ruta.
Ben Lesh

sí, todo el desafío fue cargarlo usando el atributo src de la etiqueta de script y "ofuscar" esta información en el documento.
ChuckE

Bueno, realmente no puede ocultar datos a los usuarios en una aplicación de navegador del lado del cliente. Simplemente pueden acceder a las herramientas de desarrollo de su navegador y establecer un punto de interrupción en JavaScript y examinar los objetos como quieran.
Ben Lesh

1
@Jaydipsinh, entonces necesita resolver sus problemas de CORS y usar Ajax. Hay una razón por la que los navegadores no permiten este tipo de comportamiento. La mayoría de los navegadores ni siquiera te permitirán hackear CORS con un iframe.
Ben Lesh

14

Otra solución sería hacer uso de un lenguaje de script del lado del servidor y simplemente incluir json-data en línea. Aquí hay un ejemplo que usa PHP:

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

El ejemplo anterior usa una etiqueta de script adicional con type application/json. Una solución aún más simple es incluir JSON directamente en JavaScript:

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

La ventaja de la solución con la etiqueta adicional es que el código JavaScript y los datos JSON se mantienen separados entre sí.


+ para contenido de texto. .html no me funciona en la etiqueta de script
Seth McClaine

9

Parece que esto no es posible, o al menos no es compatible.

De la especificación HTML5 :

Cuando se usa para incluir bloques de datos (a diferencia de scripts), los datos deben estar incrustados en línea , el formato de los datos se debe dar usando el atributo type, el atributo src no debe especificarse y el contenido del elemento del script debe cumplir a los requisitos definidos para el formato utilizado.


1
Parece ser una política para manejar datos como más sensibles que JS y CSS.

5

Si bien actualmente no es posible con la scriptetiqueta, es posible con una iframesi es del mismo dominio.

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

Para usar lo anterior, simplemente reemplace el atributo idy srcpor lo que necesita. El id(que asumiremos en esta situación es igual a mySpecialId) se usará para almacenar los datos en window.jsonData["mySpecialId"].

En otras palabras, para cada iframe que tenga un idy use el onloadscript, esos datos se cargarán sincrónicamente en el window.jsonDataobjeto debajo delid especificado.

Hice esto por diversión y para demostrar que es "posible", pero no recomiendo que se utilice.


Aquí hay una alternativa que usa una devolución de llamada.

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

Probado en Chrome y debería funcionar en Firefox. No estoy seguro de IE o Safari.


3

Estoy de acuerdo con Ben. No puede cargar / importar el archivo JSON simple.

Pero si absolutamente quiere hacer eso y tiene flexibilidad para actualizar el archivo json, puede

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>



1

coloque algo como esto en su archivo de script json-content.js

var mainjson = { your json data}

luego llámalo desde la etiqueta de script

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

entonces puedes usarlo en el siguiente script

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

0

Otra alternativa para usar el json exacto dentro de javascript. Como es la notación de objetos de Javascript, puede crear su objeto directamente con la notación json. Si almacena esto en un archivo .js, puede usar el objeto en su aplicación. Esta fue una opción útil para mí cuando tenía algunos datos json estáticos que quería almacenar en caché en un archivo por separado del resto de mi aplicación.

    //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
            }
        ]
    };
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.