jQuery não analisa meu JSON da consulta AJAX

88

Estou tendo dificuldade para analisar alguns dados JSON retornados do meu servidor usando jQuery.ajax ()

Para executar o AJAX, estou usando:

$.ajax({
  url: myUrl,
  cache: false,
  dataType: "json",
  success: function(data){
    ...
  },
  error: function(e, xhr){
    ...
  }
});  

E se eu retornar uma série de itens, funciona bem:

[ { title: "One", key: "1" }, { title: "Two", key: "2" } ]

A função de sucesso é chamada e recebe o objeto correto.

No entanto, quando tento retornar um único objeto:

{ title: "One", key: "1" } 

A função de erro é chamada e xhr contém 'parsererror'. Tentei colocar o JSON entre parênteses no servidor antes de enviá-lo pelo fio, mas não faz diferença. Ainda assim, se eu colar o conteúdo em uma string em Javascript e usar a função eval (), ela o avalia perfeitamente.

Alguma ideia do que estou fazendo de errado?

Anthony

littlecharva
fonte
Relacionado: stackoverflow.com/questions/631418/…
Michael Myers

Respostas:

72

O seu servidor está enviando dados como Content-Type "*/json"? Caso contrário, modifique os cabeçalhos de resposta de acordo. Enviar "application/json"seria bom, por exemplo.

Tomalak
fonte
Em segundo lugar, tive o mesmo problema uma vez e descobri que, surpreendentemente, estava usando o tipo de mímica errado. Se estiver testando em localhost no Windows, esteja atento a isso. Tente fazer upload em algum lugar e teste novamente. Se você quiser que ele funcione no localhost, você realmente precisa falsificar a solicitação.
Josh
51

De acordo com a especificação json.org , seu retorno é inválido. Os nomes são sempre citados, então você deve retornar

{ "title": "One", "key": "1" }

e

[ { "title": "One", "key": "1" }, { "title": "Two", "key": "2" } ]

Este pode não ser o problema com sua configuração, já que você diz que um deles funciona agora, mas deve ser corrigido para correção no caso de você precisar alternar para outro analisador JSON no futuro.

Ben Combee
fonte
2
Na verdade, no jQuery 1.4 (por exemplo) { key: 'val' }não é um JSON válido.
rfunduk
34

As strings JSON são colocadas entre aspas duplas ; aspas simples não são um substituto válido.

{"who": "Hello World"}

é válido, mas isso não é ...

{'who': 'Hello World'}

Embora não seja problema do OP, achei interessante notar para outros que desembarcaram aqui.

John Mee
fonte
30

Geralmente, esse problema ocorre porque sua solicitação recebeu o tipo MIME errado. Ao desenvolver no seu próprio computador, às vezes você não está recebendo o tipo MIME adequado do "servidor", que é o seu próprio computador. Eu tive esse problema uma vez ao desenvolver, abrindo o arquivo armazenado localmente no navegador (por exemplo, o url era "c: /project/test.html").

Tente usar a propriedade beforeSend para adicionar uma função de retorno de chamada que substitui o tipo MIME. Isso enganará o código, fazendo com que ele lide com json, apesar do tipo MIME errado ser enviado pelo servidor e recebido pelo seu código de chamada. Alguns exemplos de código estão abaixo.

O tipo mime apropriado é application / json de acordo com esta pergunta , mas eu sei que application / j-son funcionou quando eu tentei (agora há vários anos). Você provavelmente deve tentar o application / json primeiro.

var jsonMimeType = "application/json;charset=UTF-8";
$.ajax({
 type: "GET",
 url: myURL,
 beforeSend: function(x) {
  if(x && x.overrideMimeType) {
   x.overrideMimeType(jsonMimeType);
  }
 },
 dataType: "json",
 success: function(data){
  // do stuff...
 }
});
Josh
fonte
Só quero dizer que a sugestão beforeSend que você sugeriu funcionou para mim !! minha chamada de ajax funcionou muito bem no safari e no Chrome, mas não no Firefox. Assim que eu adicionei o beforeSend, o Firefox decolou imediatamente. Uau!! Obrigado!!
Karmen Blake
7

Eu tive esse problema e por um tempo usei

eval('('+data+')')

para obter os dados retornados em um objeto. mas mais tarde teve outros problemas para obter um erro 'ausente) entre parênteses' e descobri que jQuery tem uma função específica para avaliar uma string para uma estrutura json:

$.parseJSON(data)

deve fazer o truque. Isso além de ter sua string json no formato adequado, é claro.

Jubair
fonte
6

Se você estiver exibindo a resposta json e seus cabeçalhos não corresponderem a * / json, você pode usar a API jQuery.parseJSON integrada para analisar a resposta.

response = '{"name":"John"}';
var obj = jQuery.parseJSON(response);
alert( obj.name === "John" );
Nezzy
fonte
4
{ title: "One", key: "1" }

Não é o que você pensa. Como uma expressão, é um literal de objeto, mas como uma declaração, é:

{                // new block
    title:       // define a label called 'title' for goto statements
        "One",   // statement: the start of an expression which will be ignored
        key:     // ...er, what? you can't have a goto label in the middle of an expression
                 // ERROR

Infelizmente eval () não fornece uma maneira de especificar se você está fornecendo uma instrução ou uma expressão, e tende a adivinhar errado.

A solução usual é colocar qualquer coisa entre parênteses antes de enviar para a função eval (). Você diz que tentou isso no servidor ... claramente, de alguma forma, isso não está funcionando. Deve ser à prova d'água para dizer do lado do cliente, o que quer que esteja recebendo a resposta XMLHttpRequest:

eval('('+responseText+')');

ao invés de:

eval(responseText);

contanto que a resposta seja realmente uma expressão, não uma declaração. (por exemplo, não tem várias cláusulas separadas por ponto e vírgula ou nova linha.)

bobince
fonte
Acho que o jQuery adiciona os parênteses automaticamente ao processar os dados da solicitação.
strager
2
Essa resposta foi muito útil para mim, pois nunca entendi por que as pessoas colocam JSON entre parênteses.
Andrey Tarantsov
3

Você terá que definir o tipo de conteúdo do cabeçalho em seu php assim:

 <?php

 header('Content-type:application/json');

 ?>

Assista a estes vídeos para melhor compreensão ....

Referência: http://www.youtube.com/watch?v=EvFXWqEqh6o

user3612872
fonte
2

Se você estiver consumindo ASP.NET Web Services usando jQuery, certifique-se de incluir o seguinte em seu web.config:

<webServices>
    <protocols>
        <add name="HttpGet"/>
        <add name="HttpPost"/>
    </protocols>
</webServices>
Andreas Grech
fonte
2

Eu tive um problema semelhante a este em que o Firefox 3.5 funcionou bem e analisou meus dados JSON, mas o Firefox 3.0.6 retornou um erro de análise. Acontece que era um espaço em branco no início do JSON que fez o Firefox 3.0.6 gerar um erro. Remover o espaço em branco consertou

Jonburney
fonte
2

As técnicas "eval ()" e "JSON.parse ()" usam formatos mutuamente exclusivos.

  • Com "eval ()", os parênteses são obrigatórios .
  • Com "JSON.parse ()" parênteses são proibidos .

Cuidado, existem funções "stringify ()" que produzem o formato "eval". Para ajax, você deve usar apenas o formato JSON.

Enquanto "eval" incorpora toda a linguagem JavaScript, JSON usa apenas um pequeno subconjunto da linguagem. Entre as construções na linguagem JavaScript que "eval" deve reconhecer está a "instrução Block" (também conhecida como "instrução composta") ; que é um par ou chaves "{}" com algumas declarações dentro. Mas as chaves também são usadas na sintaxe de literais de objeto. A interpretação é diferenciada pelo contexto em que o código aparece. Algo pode parecer um objeto literal para você, mas "eval" o verá como uma instrução composta.

Na linguagem JavaScript, os literais de objeto ocorrem à direita de uma atribuição.

var myObj = { ...some..code..here... };

Literais de objeto não ocorrem por conta própria.

{ ...some..code..here... }   // this looks like a compound statement

Voltando à pergunta original do OP, feita em 2008, ele perguntou por que o seguinte falha em "eval ()":

{ title: "One", key: "1" }

A resposta é que se parece com uma declaração composta. Para convertê-lo em um objeto, você deve colocá-lo em um contexto em que uma instrução composta seja impossível. Isso é feito colocando-se entre parênteses

( { title: "One", key: "1" } )    // not a compound statment, so must be object literal

O OP também perguntou por que uma declaração semelhante foi avaliada com sucesso:

[ { title: "One", key: "1" }, { title: "Two", key: "2" } ]

A mesma resposta se aplica - as chaves estão em um contexto em que uma declaração composta é impossível. Este é um contexto de array, " [...]", e os arrays podem conter objetos, mas não podem conter instruções.

Ao contrário de "eval ()", JSON é muito limitado em seus recursos. A limitação é intencional. O designer de JSON pretendia um subconjunto minimalista de JavaScript, usando apenas sintaxe que poderia aparecer no lado direito de uma atribuição. Então, se você tiver algum código que analisa corretamente em JSON ...

var myVar = JSON.parse("...some...code...here...");

... isso implica que também será analisado legalmente no lado direito de uma atribuição, como este ..

var myVar = ...some..code..here... ;

Mas essa não é a única restrição do JSON. A especificação da linguagem BNF para JSON é muito simples. Por exemplo, não permite o uso de aspas simples para indicar strings (como JavaScript e Perl fazem) e não tem uma maneira de expressar um único caractere como um byte (como 'C' faz). Infelizmente, também não permite comentários (o que seria muito bom ao criar arquivos de configuração). A vantagem de todas essas limitações é que a análise de JSON é rápida e não oferece oportunidade para injeção de código (uma ameaça à segurança).

Devido a essas limitações, JSON não usa parênteses. Consequentemente, um parêntese em uma string JSON é um caractere ilegal.

Sempre use o formato JSON com ajax, pelos seguintes motivos:

  • Um pipeline de ajax típico será configurado para JSON.
  • O uso de "eval ()" será criticado como um risco de segurança.

Como um exemplo de pipeline de ajax, considere um programa que envolve um servidor Node e um cliente jQuery. O programa cliente usa uma chamada jQuery com o formulário $.ajax({dataType:'json',...etc.});. O JQuery cria um objeto jqXHR para uso posterior, em seguida, empacota e envia a solicitação associada. O servidor aceita a solicitação, processa-a e está pronto para responder. O programa do servidor chamará o método res.json(data)para empacotar e enviar a resposta. De volta ao lado do cliente, o jQuery aceita a resposta, consulta o objeto jqXHR associado e processa os dados formatados em JSON. Tudo isso funciona sem a necessidade de conversão manual de dados. A resposta não envolve nenhuma chamada explícita para JSON.stringify () no servidor Node e nenhuma chamada explícita para JSON.parse () no cliente; está tudo resolvido para você.

O uso de "eval" está associado a riscos de segurança de injeção de código. Você pode pensar que não há como isso acontecer, mas os hackers podem ser bem criativos. Além disso, "eval" é problemático para a otimização Javascript.

Se você estiver usando uma função "stringify ()", saiba que algumas funções com esse nome criarão cadeias de caracteres compatíveis com "eval" e não com JSON. Por exemplo, no Node, o seguinte fornece a função que cria strings em formato compatível com "eval":

var stringify = require('node-stringify'); // generates eval() format

Isso pode ser útil, mas a menos que você tenha uma necessidade específica, provavelmente não é o que você deseja.

IAM_AL_X
fonte
1

Se retornar uma matriz funciona e retornar um único objeto não, você também pode tentar retornar seu único objeto como uma matriz contendo esse único objeto:

[ { title: "One", key: "1" } ]

dessa forma, você está retornando uma estrutura de dados consistente, uma matriz de objetos, não importa a carga de dados.

Vejo que você tentou envolver seu único objeto entre "parênteses" e sugeriu isso com um exemplo porque é claro que o JavaScript trata [..] de maneira diferente de (..)

David Alpert
fonte
1

Se o manipulador de erros do jQuery estiver sendo chamado e o objeto XHR contiver "erro do analisador", provavelmente é um erro do analisador retornando do servidor.

O seu cenário de resultados múltiplos é quando você chama o serviço sem um parâmetro, mas ele falha quando você tenta fornecer um parâmetro para recuperar o registro único?

De qual backend você está retornando?

Em serviços ASMX, por exemplo, geralmente é o caso quando os parâmetros são fornecidos ao jQuery como um objeto JSON em vez de uma string JSON. Se você fornecer ao jQuery um objeto JSON real para seu parâmetro "dados", ele o serializará em pares k, v padrão e delimitados em vez de enviá-lo como JSON.

Dave Ward
fonte
1

Descobri em algumas de minhas implementações que tive que adicionar:

obj = new Object; obj = (data.obj);

o que parecia resolver o problema. Eval ou não, parecia fazer exatamente o mesmo por mim.

Jay
fonte
Use o literal de objeto ao inicializar um novo objeto, não o construtor de objeto: var obj = {};
Andreas Grech
Sim, entendo, var myArray = [] para matrizes e var myObject = {}, obrigado pela dica Dreas
Jay,
1

jQuery engasga com certas chaves JSON. Eu estava enviando este snippet JSON em PHP:

echo json_encode((object) array('result' => 'success'));

Renomear a chave 'resultado' para outra coisa funciona. Eu diria que esta é uma colisão de palavras reservadas de algum tipo e pode ser um bug no jQuery (1.4.2).

Jonathon Hill
fonte
1

Em um ambiente ColdFusion, uma coisa que causará um erro, mesmo com JSON bem formado, é ativar a opção Enable Request Debugging Output no ColdFusion Administrator (em Debugging & Logging> Debug Output Settings). As informações de depuração serão retornadas com os dados JSON e, portanto, os invalidarão.

Dave DuPlantis
fonte
1

também tente isso

$.ajax({
    url: url,
    data:datas,
    success:function(datas, textStatus, jqXHR){
    var returnedData = jQuery.parseJSON(datas.substr(datas.indexOf('{')));
})};

no meu caso, o servidor responde com um caractere desconhecido antes de '{'

valir
fonte
1

Estava recebendo status = parseerror e xhr.status = 200.

O problema para mim era que o URL dentro da resposta JSON tinha '\' mudar para '/' corrigido.

Brent
fonte
0

Eu estava lutando com isso e passei algumas horas tentando descobrir isso, até que usei o firebug para mostrar o objeto de dados.

var data = eval("(" + data.responseText + ")");
console.log(data.count);
webwiseguys
fonte
-1

usar

$data = yourarray(); 
json_encode($data)

no lado do servidor. No lado do cliente, use ajax com tipo de dados JSON e certifique-se de que a codificação do documento não seja UTF-8 com BOM, mas sim UTF-8.

user2854865
fonte