jQuery no analizará mi JSON de la consulta AJAX


88

Tengo dificultades para analizar algunos datos JSON devueltos desde mi servidor usando jQuery.ajax ()

Para realizar el AJAX que estoy usando:

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

Y si devuelvo una variedad de elementos, entonces funciona bien:

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

Se llama a la función de éxito y recibe el objeto correcto.

Sin embargo, cuando intento devolver un solo objeto:

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

Se llama a la función de error y xhr contiene 'parsererror'. Intenté envolver el JSON entre paréntesis en el servidor antes de enviarlo por el cable, pero no hace ninguna diferencia. Sin embargo, si pego el contenido en una cadena en Javascript y luego uso la función eval (), lo evalúa perfectamente.

¿Alguna idea de lo que estoy haciendo mal?

Antonio


Respuestas:


72

¿Su servidor envía datos como tipo de contenido "*/json"? De lo contrario, modifique los encabezados de respuesta en consecuencia. Enviar "application/json"estaría bien, por ejemplo.


En segundo lugar esta suposición, tuve el mismo problema una vez y aprendí que, sorprendentemente, estaba usando el tipo de mimo incorrecto. Si está probando sobre localhost en Windows, sea muy consciente de esto. Intente cargarlo en algún lugar y probarlo nuevamente. Si desea que funcione en localhost, realmente tiene que modificar la solicitud.
Josh

51

De acuerdo con la especificación de json.org , su devolución no es válida. Los nombres siempre se citan, por lo que debería volver

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

y

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

Puede que este no sea el problema con su configuración, ya que dice que uno de ellos funciona ahora, pero debería corregirse para que sea correcto en caso de que necesite cambiar a otro analizador JSON en el futuro.


2
De hecho, en jQuery 1.4 (por ejemplo) { key: 'val' }no es JSON válido.
rfunduk

34

Las cadenas JSON están envueltas entre comillas dobles ; las comillas simples no son un sustituto válido.

{"who": "Hello World"}

es válido pero esto no es ...

{'who': 'Hello World'}

Si bien no es un problema del OP, creo que vale la pena señalarlo para otros que aterrizan aquí.


30

Este problema suele deberse a que su solicitud recibió el tipo de mime incorrecto. Al desarrollar en su propia computadora, a veces no está recibiendo el tipo de mime adecuado del "servidor", que es su propia computadora. Me encontré con este problema una vez al desarrollar abriendo el archivo almacenado localmente en el navegador (por ejemplo, la URL era "c: /project/test.html").

Intente usar la propiedad beforeSend para agregar una función de devolución de llamada que anule el tipo mime. Esto engañará al código para que trate con json a pesar de que el servidor envía el tipo de mime incorrecto y el código de llamada lo recibe. A continuación se muestra un código de ejemplo.

El tipo de mimo adecuado es application / json de acuerdo con esta pregunta , pero sé que application / j-son funcionó cuando lo probé (ahora hace varios años). Probablemente deberías probar application / json primero.

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...
 }
});

¡Solo quiero decir que la sugerencia de beforeSend que sugieres funcionó para mí! mi llamada ajax funcionó muy bien en safari y chrome pero no en firefox. Tan pronto como agregué el beforeSend, Firefox despegó. ¡¡Guau!! ¡¡Gracias!!
Karmen Blake

7

Tuve este problema y por un tiempo usé

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

para obtener los datos devueltos en un objeto. pero luego tuvo otros problemas al obtener un error 'faltante) entre paréntesis' y descubrí que jQuery tiene una función específicamente para evaluar una cadena para una estructura json:

$.parseJSON(data)

debería hacer el truco. Esto es además de tener su cadena json en el formato adecuado, por supuesto.


6

Si está repitiendo la respuesta json y sus encabezados no coinciden con * / json, puede usar la api jQuery.parseJSON incorporada para analizar la respuesta.

response = '{"name":"John"}';
var obj = jQuery.parseJSON(response);
alert( obj.name === "John" );

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

No es lo que piensas. Como expresión, es un objeto literal, pero como declaración, es:

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

Desafortunadamente, eval () no le da una forma de especificar si le está dando una declaración o una expresión, y tiende a adivinar mal.

La solución habitual es, de hecho, envolver cualquier cosa entre paréntesis antes de enviarlo a la función eval (). Dices que lo has intentado en el servidor ... claramente, de alguna manera, eso no funciona. Debería ser impermeable decir en el extremo del cliente, lo que sea que reciba la respuesta XMLHttpRequest:

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

en vez de:

eval(responseText);

siempre que la respuesta sea realmente una expresión, no una declaración. (por ejemplo, no tiene varias cláusulas separadas por punto y coma o líneas nuevas).


Creo que jQuery agrega los paréntesis automáticamente al procesar los datos de la solicitud.
extraño

2
Esta respuesta fue muy útil para mí, ya que nunca entendí por qué las personas envuelven JSON entre paréntesis.
Andrey Tarantsov


2

Si está consumiendo ASP.NET Web Services usando jQuery, asegúrese de tener lo siguiente incluido en su web.config:

<webServices>
    <protocols>
        <add name="HttpGet"/>
        <add name="HttpPost"/>
    </protocols>
</webServices>

2

Tuve un problema similar a este en el que Firefox 3.5 funcionó bien y analizó mis datos JSON, pero Firefox 3.0.6 devolvió un error de análisis. Resultó que era un espacio en blanco al comienzo del JSON lo que provocó que Firefox 3.0.6 arrojara un error. Quitar el espacio en blanco lo arregló


2

Las técnicas "eval ()" y "JSON.parse ()" utilizan formatos mutuamente excluyentes.

  • Con "eval ()" se requieren paréntesis .
  • Con "JSON.parse ()" los paréntesis están prohibidos .

Tenga cuidado, hay funciones "stringify ()" que producen el formato "eval". Para ajax, debe usar solo el formato JSON.

Mientras que "eval" incorpora todo el lenguaje JavaScript, JSON usa solo un pequeño subconjunto del lenguaje. Entre las construcciones en el lenguaje JavaScript que "eval" debe reconocer está la "declaración de bloque" (también conocida como "declaración compuesta") ; que es un par o llaves "{}" con algunas declaraciones dentro. Pero las llaves también se utilizan en la sintaxis de los objetos literales. La interpretación se diferencia por el contexto en el que aparece el código. Algo puede parecerle un objeto literal, pero "eval" lo verá como una declaración compuesta.

En el lenguaje JavaScript, los objetos literales aparecen a la derecha de una asignación.

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

Los objetos literales no ocurren por sí solos.

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

Volviendo a la pregunta original del OP, formulada en 2008, preguntó por qué lo siguiente falla en "eval ()":

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

La respuesta es que parece una declaración compuesta. Para convertirlo en un objeto, debe ponerlo en un contexto donde una declaración compuesta es imposible. Eso se hace poniendo paréntesis alrededor.

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

El PO también preguntó por qué una declaración similar hizo con éxito eval:

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

Se aplica la misma respuesta: las llaves se encuentran en un contexto en el que una declaración compuesta es imposible. Este es un contexto de matriz, " [...]" y las matrices pueden contener objetos, pero no pueden contener declaraciones.

A diferencia de "eval ()", JSON es muy limitado en sus capacidades. La limitación es intencionada. El diseñador de JSON pretendía un subconjunto minimalista de JavaScript, utilizando solo la sintaxis que podría aparecer en el lado derecho de una tarea. Entonces, si tiene algún código que se analiza correctamente en JSON ...

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

... eso implica que también analizará legalmente en el lado derecho de una asignación, como esta ...

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

Pero esa no es la única restricción en JSON. La especificación del lenguaje BNF para JSON es muy simple. Por ejemplo, no permite el uso de comillas simples para indicar cadenas (como lo hacen JavaScript y Perl) y no tiene una forma de expresar un solo carácter como un byte (como lo hace 'C'). Desafortunadamente, tampoco permite comentarios (lo que sería muy bueno al crear archivos de configuración). La ventaja de todas esas limitaciones es que el análisis de JSON es rápido y no ofrece la oportunidad de inyectar código (una amenaza a la seguridad).

Debido a estas limitaciones, JSON no utiliza paréntesis. En consecuencia, un paréntesis en una cadena JSON es un carácter ilegal.

Utilice siempre el formato JSON con ajax, por las siguientes razones:

  • Se configurará una canalización ajax típica para JSON.
  • El uso de "eval ()" será criticado como un riesgo de seguridad.

Como ejemplo de una canalización ajax, considere un programa que involucra un servidor Node y un cliente jQuery. El programa cliente usa una llamada jQuery que tiene el formulario $.ajax({dataType:'json',...etc.});. JQuery crea un objeto jqXHR para su uso posterior, luego empaqueta y envía la solicitud asociada. El servidor acepta la solicitud, la procesa y luego está listo para responder. El programa servidor llamará al método res.json(data)para empaquetar y enviará la respuesta. De vuelta en el lado del cliente, jQuery acepta la respuesta, consulta el objeto jqXHR asociado y procesa los datos formateados JSON. Todo esto funciona sin necesidad de conversión manual de datos. La respuesta no implica una llamada explícita a JSON.stringify () en el servidor Node, ni una llamada explícita a JSON.parse () en el cliente; todo eso se maneja por ti.

El uso de "eval" está asociado con riesgos de seguridad de inyección de código. Puede pensar que eso no puede suceder de ninguna manera, pero los piratas informáticos pueden ser bastante creativos. Además, "eval" es problemático para la optimización de Javascript.

Si se encuentra usando una función "stringify ()", tenga en cuenta que algunas funciones con ese nombre crearán cadenas que son compatibles con "eval" y no con JSON. Por ejemplo, en Node, lo siguiente le brinda una función que crea cadenas en formato compatible con "eval":

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

Esto puede ser útil, pero a menos que tenga una necesidad específica, probablemente no sea lo que desea.


1

Si devolver una matriz funciona y devolver un solo objeto no, también puede intentar devolver su único objeto como una matriz que contiene ese único objeto:

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

de esa manera, está devolviendo una estructura de datos consistente, una matriz de objetos, sin importar la carga útil de datos.

Veo que ha intentado envolver su único objeto entre "paréntesis", y sugiero esto con un ejemplo porque, por supuesto, JavaScript trata [..] de manera diferente a (..)


1

Si se llama al controlador de errores de jQuery y el objeto XHR contiene "error del analizador", probablemente se trate de un error del analizador procedente del servidor.

¿Es su escenario de resultados múltiples cuando llama al servicio sin un parámetro, pero se rompe cuando intenta proporcionar un parámetro para recuperar el registro único?

¿De qué backend estás devolviendo esto?

En los servicios ASMX, por ejemplo, ese suele ser el caso cuando los parámetros se suministran a jQuery como un objeto JSON en lugar de una cadena JSON. Si proporciona a jQuery un objeto JSON real para su parámetro de "datos", lo serializará en pares k, v estándar y delimitados en lugar de enviarlo como JSON.


1

Encontré en algunas de mis implementaciones que tuve que agregar:

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

que parecía resolver el problema. Evalúe o no, parecía hacer exactamente lo mismo para mí.


Use el literal de objeto al inicializar un nuevo objeto, no el constructor de Objeto: var obj = {};
Andreas Grech

Sí, ya veo, var myArray = [] para matrices y var myObject = {}, gracias por el consejo Dreas
Jay

1

jQuery se ahoga con ciertas claves JSON. Estaba enviando este fragmento de JSON en PHP:

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

Cambiar el nombre de la clave 'resultado' a otra cosa funciona. Supongo que esta es una colisión de palabras reservada de algún tipo, y podría ser un error en jQuery (1.4.2).


1

En un entorno ColdFusion, una cosa que provocará un error, incluso con JSON bien formado, es tener activada la salida de depuración de solicitudes activada en el administrador de ColdFusion (en Depuración y registro> Configuración de salida de depuración). La información de depuración se devolverá con los datos JSON y, por lo tanto, la invalidará.


1

también prueba esto

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

en mi caso, el servidor responde con un carácter desconocido antes de '{'


1

Estaba obteniendo status = parseerror y xhr.status = 200.

El problema para mí fue que la URL dentro de la respuesta JSON tenía '\' cambiando a '/' solucionó esto.


0

Estaba luchando con esto y pasé algunas horas tratando de resolverlo, hasta que usé firebug para mostrar el objeto de datos.

var data = eval("(" + data.responseText + ")");
console.log(data.count);

-1

utilizar

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

en el lado del servidor. En el lado del cliente, use ajax con Datatype JSON y asegúrese de que la codificación de su documento no sea UTF-8 con BOM, tiene que ser UTF-8.

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.