HTML / Javascript: como acessar dados JSON carregados em uma tag de script com conjunto src


91

Tenho este arquivo JSON que gero no servidor que desejo tornar acessível no cliente, pois a página pode ser visualizada. Basicamente, o que eu quero alcançar é:

Eu tenho a seguinte tag declarada em meu documento html:

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

O arquivo referido em sua fonte contém dados JSON. Como vi, os dados foram baixados, assim como acontece com os scripts.

Agora, como faço para acessar em Javascript? Eu tentei acessar a tag de script, com e sem jQuery, usando uma variedade de métodos para tentar obter meus dados JSON, mas de alguma forma isso não funciona. Primeiros seu innerHTMLteria funcionado tinha os dados JSON sido escrito em linha no script. O que não era e não é o que estou tentando alcançar.

Solicitação JSON remota após o carregamento da página também não é uma opção, caso você queira sugerir isso.


3
Em vez de um arquivo json, torne-o um arquivo javascript que atribui o objeto a uma variável. A outra abordagem é usar ajax.
Asad Saeeduddin de

3
A primeira sugestão é a implementação atual. Eu gostaria de não fazer isso porque estou usando o comportamento para entregar estrutura. Eu prefiro usar estrutura para estrutura (se eu quiser JSON, vou buscar JSON). A segunda sugestão não é desejada (preciso desses dados para o processo de inicialização).
ChuckE

1
@ChuckE por meio de uma <script>tag ou AJAX, você ainda terá que esperar a conclusão de uma solicitação HTTP adicional. O navegador não permitirá que você leia o conteúdo do script se você buscá-lo com um atributo "src", então sua única alternativa é fazer uma solicitação AJAX.
Pointy de

3
@Pointy através de uma tag <script>, as coisas serão avaliadas assim que forem baixadas. Se eu colocar meu script json antes do meu script js, os dados do script json serão avaliados antes dos dados do script js, ou seja, não vou esperar, os dados já estão lá. Sobre ser minha única alternativa, gostaria de ver alguma documentação oficial antes de concordar com você (não estou dizendo que você está errado, apenas esse foi exatamente o motivo pelo qual escrevi a pergunta).
ChuckE

2
"Solicitação JSON remota após o carregamento da página também não é uma opção, caso você queira sugerir isso." ... como uma solicitação JSON é tão diferente de uma solicitação enviada por um <script src=""></script>? Ambos farão chamadas GET em seu servidor.
Ben Lesh

Respostas:


116

Você não pode carregar JSON assim, desculpe.

Eu sei que você está pensando "por que não posso simplesmente usar srcaqui? Já vi coisas assim ...":

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

... bem, para simplificar, foi apenas a tag do script sendo "abusada" como portadora de dados. Você pode fazer isso com todos os tipos de dados. Por exemplo, muitos mecanismos de modelagem utilizam tags de script para conter modelos .

Você tem uma pequena lista de opções para carregar seu JSON de um arquivo remoto:

  1. Use $.get('your.json')ou algum outro método AJAX.
  2. Escreva um arquivo que defina uma variável global para seu json. (parece piegas).
  3. Coloque-o em um iframe invisível e raspe o conteúdo depois de carregado (chamo isso de "modo 1997")
  4. Consulte um sacerdote vodu.

Ponto final:

Solicitação JSON remota após o carregamento da página também não é uma opção, caso você queira sugerir isso.

... isso não faz sentido. A diferença entre uma solicitação AJAX e uma solicitação enviada pelo navegador durante o processamento de seu <script src="">é essencialmente nada. Ambos farão um GET no recurso. HTTP não se importa se é feito por causa de uma tag de script ou uma chamada AJAX, e nem o seu servidor.


5
Ótima resposta. Quando você diz "a tag de script está sendo 'abusada'", quer dizer que é um uso incorreto (talvez não errado, mas "criativo") da tag de script? O seu n. 2 opção é a que já temos em produção, eu estava procurando uma solução estritamente json / no-js, por pura experimentação (estou bem de que não seja possível se tenho certeza que é). Com relação ao ponto final, preciso dessas informações antes do evento onload e não quero fazer com que toda a inicialização dependa de uma solicitação assíncrona que pode variar no tempo de conclusão. Esta é a principal diferença entre a chamada Ajax e a tag de script.
ChuckE

1
Não, eu não acho que seja "errado", digamos, apenas ... "criativo" é provavelmente uma boa palavra para isso. Se realmente escrever o JSON na <script>tag for possível, eu iria por esse caminho, eu acho.
Ben Lesh

sim, todo o desafio foi carregá-lo usando o atributo src da tag script e "ofuscar" essas informações no documento.
ChuckE

Bem, você não pode realmente ocultar dados de usuários em um aplicativo de navegador do lado do cliente. Eles podem simplesmente acessar as ferramentas de desenvolvedor de seu navegador e definir um ponto de interrupção no JavaScript e examinar os objetos como quiserem.
Ben Lesh

1
@Jaydipsinh, então você precisa resolver seus problemas de CORS e usar Ajax. Há um motivo pelo qual os navegadores não permitem esse tipo de comportamento. A maioria dos navegadores nem deixa você invadir o CORS com um iframe mais.
Ben Lesh

14

Outra solução seria usar uma linguagem de script do lado do servidor e simplesmente incluir json-data inline. Aqui está um exemplo que usa PHP:

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

O exemplo acima usa uma tag de script extra com tipo application/json. Uma solução ainda mais simples é incluir o JSON diretamente no JavaScript:

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

A vantagem da solução com a tag extra é que o código JavaScript e os dados JSON são mantidos separados um do outro.


+ para conteúdo de texto. .html não funciona para mim na tag de script
Seth McClaine

9

Parece que isso não é possível, ou pelo menos não é compatível.

Da especificação HTML5 :

Quando usado para incluir blocos de dados (ao contrário de scripts), os dados devem ser embutidos , o formato dos dados deve ser fornecido usando o atributo type, o atributo src não deve ser especificado e o conteúdo do elemento script deve estar em conformidade aos requisitos definidos para o formato utilizado.


1
Parece ser uma política lidar com dados como mais confidenciais do que JS e CSS.

5

Embora atualmente não seja possível com a scripttag, é possível com um iframese for do mesmo domínio.

<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 o acima, basta substituir o atributo ide srcpelo que você precisa. O id(que assumiremos nesta situação é igual a mySpecialId) será usado para armazenar os dados em window.jsonData["mySpecialId"].

Em outras palavras, para cada iframe que possui um ide usa o onloadscript terá esses dados carregados de forma síncrona no window.jsonDataobjeto sob o idespecificado.

Fiz isso por diversão e para mostrar que é "possível", mas não recomendo que seja usado.


Aqui está uma alternativa que usa um retorno de chamada.

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

Testado em cromo e deve funcionar no firefox. Não tenho certeza sobre o IE ou Safari.


3

Eu concordo com Ben. Você não pode carregar / importar o arquivo JSON simples.

Mas se você realmente deseja fazer isso e tem flexibilidade para atualizar o arquivo json, você pode

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 assim no seu arquivo de script json-content.js

var mainjson = { your json data}

em seguida, chame-o da tag do script

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

então você pode usá-lo no próximo script

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

0

Outra alternativa para usar o json exato dentro do javascript. Como é Javascript Object Notation, você pode simplesmente criar seu objeto diretamente com a notação json. Se você armazenar isso em um arquivo .js, poderá usar o objeto em seu aplicativo. Essa foi uma opção útil para mim quando eu tinha alguns dados json estáticos que queria armazenar em cache em um arquivo separado do resto do meu aplicativo.

    //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
            }
        ]
    };
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.