jQuery n'analysera pas mon JSON à partir de la requête AJAX


88

J'ai des difficultés à analyser certaines données JSON renvoyées par mon serveur à l'aide de jQuery.ajax ()

Pour effectuer l'AJAX que j'utilise:

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

Et si je retourne un tableau d'articles, cela fonctionne bien:

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

La fonction de succès est appelée et reçoit l'objet correct.

Cependant, lorsque j'essaye de renvoyer un seul objet:

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

La fonction d'erreur est appelée et xhr contient «parsererror». J'ai essayé de mettre le JSON entre parenthèses sur le serveur avant de l'envoyer sur le fil, mais cela ne fait aucune différence. Pourtant, si je colle le contenu dans une chaîne en Javascript et que j'utilise ensuite la fonction eval (), il l'évalue parfaitement.

Des idées sur ce que je fais mal?

Anthony


Réponses:


72

Votre serveur envoie-t-il des données en tant que type de contenu "*/json"? Sinon, modifiez les en-têtes de réponse en conséquence. L'envoi "application/json"serait bien, par exemple.


Deuxièmement, j'ai eu le même problème une fois et j'ai appris que, étonnamment, j'utilisais le mauvais type de mime. Si vous testez sur localhost sur Windows, soyez très conscient de cela. Essayez de le télécharger quelque part et de le tester à nouveau. Si vous voulez que cela fonctionne sur localhost, vous devez vraiment truquer la demande.
Josh

51

Selon la spécification json.org , votre retour n'est pas valide. Les noms sont toujours cités, vous devriez donc revenir

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

et

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

Ce n'est peut-être pas le problème avec votre configuration, puisque vous dites que l'un d'eux fonctionne maintenant, mais il devrait être corrigé pour être correct au cas où vous auriez besoin de passer à un autre analyseur JSON à l'avenir.


2
En effet, dans jQuery 1.4 (par exemple) ce { key: 'val' }n'est pas JSON valide.
rfunduk

34

Les chaînes JSON sont entourées de guillemets doubles ; les guillemets simples ne sont pas un substitut valide.

{"who": "Hello World"}

est valide mais ce n'est pas ...

{'who': 'Hello World'}

Bien que ce ne soit pas le problème du PO, je pense qu'il vaut la peine de le noter pour les autres qui atterrissent ici.


30

Ce problème est généralement dû au fait que votre demande a reçu le mauvais type de mime. Lorsque vous développez sur votre propre ordinateur, vous ne recevez parfois pas le type mime approprié du "serveur", qui est votre propre ordinateur. J'ai rencontré ce problème une fois lors du développement en ouvrant le fichier stocké localement dans le navigateur (par exemple, l'url était "c: /project/test.html").

Essayez d'utiliser la propriété beforeSend pour ajouter une fonction de rappel qui remplace le type mime. Cela incitera le code à traiter json malgré le mauvais type de mime envoyé par le serveur et reçu par votre code d'appel. Un exemple de code est ci-dessous.

Le type de mime approprié est application / json selon cette question , mais je sais que application / j-son fonctionnait lorsque je l'ai essayé (il y a maintenant plusieurs années). Vous devriez probablement essayer application / json en premier.

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

je veux juste dire que la suggestion beforeSend que vous suggérez a fonctionné pour moi !! mon appel ajax a très bien fonctionné dans safari et chrome mais pas dans firefox. dès que j'ai ajouté le beforeSend, Firefox a pris son envol. sensationnel!! Merci!!
Karmen Blake

7

J'ai eu ce problème et pendant un moment j'ai utilisé

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

pour récupérer les données renvoyées dans un objet. mais plus tard, il y a eu d'autres problèmes pour obtenir une erreur `` manquant) entre parenthèses '' et j'ai découvert que jQuery avait une fonction spécifiquement pour évaluer une chaîne pour une structure json:

$.parseJSON(data)

devrait faire l'affaire. C'est en plus d'avoir votre chaîne json dans le bon format bien sûr.


6

Si vous faites écho à la réponse json et que vos en-têtes ne correspondent pas à * / json, vous pouvez utiliser l'API intégrée jQuery.parseJSON pour analyser la réponse.

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

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

N'est-ce pas ce que vous pensez. En tant qu'expression, c'est un littéral Object, mais en tant qu'instruction, c'est:

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

Malheureusement eval () ne vous donne pas le moyen de spécifier si vous lui donnez une instruction ou une expression, et il a tendance à se tromper.

La solution habituelle est en effet de mettre n'importe quoi entre parenthèses avant de l'envoyer à la fonction eval (). Vous dites que vous avez essayé cela sur le serveur ... de toute évidence, cela ne passe pas. Il doit être étanche pour dire du côté client, tout ce qui reçoit la réponse XMLHttpRequest:

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

au lieu de:

eval(responseText);

tant que la réponse est vraiment une expression et non une déclaration. (par exemple, il n'a pas plusieurs clauses séparées par un point-virgule ou une nouvelle ligne.)


Je pense que jQuery ajoute automatiquement les parenthèses lors du traitement des données de la demande.
strager

2
Cette réponse m'a été très utile, car je n'ai jamais compris pourquoi les gens mettent JSON entre parenthèses.
Andrey Tarantsov


2

Si vous utilisez les services Web ASP.NET à l'aide de jQuery, assurez-vous que les éléments suivants sont inclus dans votre web.config:

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

2

J'ai eu un problème similaire à celui-ci où Firefox 3.5 fonctionnait bien et analysait mes données JSON mais Firefox 3.0.6 a renvoyé une erreur d'analyse. Il s'est avéré que c'était un espace vide au début du JSON qui a provoqué une erreur de Firefox 3.0.6. La suppression de l'espace vide l'a corrigé


2

Les techniques "eval ()" et "JSON.parse ()" utilisent des formats mutuellement exclusifs.

  • Avec "eval ()" les parenthèses sont obligatoires .
  • Avec "JSON.parse ()" les parenthèses sont interdites .

Attention, il existe des fonctions "stringify ()" qui produisent le format "eval". Pour ajax, vous ne devez utiliser que le format JSON.

Alors que «eval» incorpore le langage JavaScript entier, JSON n'utilise qu'un petit sous-ensemble du langage. Parmi les constructions du langage JavaScript que «eval» doit reconnaître, il y a la «déclaration de bloc» (alias «instruction composée») ; qui est une paire ou des accolades "{}" avec quelques déclarations à l'intérieur. Mais les accolades sont également utilisées dans la syntaxe des littéraux d'objet. L'interprétation est différenciée par le contexte dans lequel le code apparaît. Quelque chose peut ressembler à un objet littéral pour vous, mais "eval" le verra comme une instruction composée.

Dans le langage JavaScript, les littéraux d'objet apparaissent à droite d'une affectation.

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

Les littéraux d'objet ne se produisent pas d'eux-mêmes.

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

Revenant à la question initiale du PO, posée en 2008, il a demandé pourquoi ce qui suit échoue dans "eval ()":

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

La réponse est que cela ressemble à une instruction composée. Pour le convertir en objet, vous devez le placer dans un contexte où une instruction composée est impossible. Cela se fait en mettant des parenthèses autour

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

Le PO a également demandé pourquoi une déclaration similaire avait réussi à évaluer:

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

La même réponse s'applique - les accolades sont dans un contexte où une instruction composée est impossible. Il s'agit d'un contexte de tableau, " [...]", et les tableaux peuvent contenir des objets, mais ils ne peuvent pas contenir d'instructions.

Contrairement à "eval ()", JSON est très limité dans ses capacités. La limitation est intentionnelle. Le concepteur de JSON a conçu un sous-ensemble minimaliste de JavaScript, utilisant uniquement la syntaxe qui pourrait apparaître sur le côté droit d'une affectation. Donc, si vous avez du code qui analyse correctement en JSON ...

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

... cela implique qu'il analysera également légalement le côté droit d'une affectation, comme ceci.

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

Mais ce n'est pas la seule restriction sur JSON. La spécification du langage BNF pour JSON est très simple. Par exemple, il ne permet pas l'utilisation de guillemets simples pour indiquer des chaînes (comme le font JavaScript et Perl) et il n'a pas de moyen d'exprimer un seul caractère sous forme d'octet (comme le fait «C»). Malheureusement, il n'autorise pas non plus les commentaires (ce qui serait vraiment bien lors de la création de fichiers de configuration). L'avantage de toutes ces limitations est que l'analyse JSON est rapide et n'offre aucune possibilité d'injection de code (une menace pour la sécurité).

En raison de ces limitations, JSON n'a aucune utilité pour les parenthèses. Par conséquent, une parenthèse dans une chaîne JSON est un caractère non autorisé.

Utilisez toujours le format JSON avec ajax, pour les raisons suivantes:

  • Un pipeline ajax typique sera configuré pour JSON.
  • L'utilisation de "eval ()" sera critiquée comme un risque de sécurité.

Comme exemple de pipeline ajax, considérons un programme qui implique un serveur Node et un client jQuery. Le programme client utilise un appel jQuery ayant la forme $.ajax({dataType:'json',...etc.});. JQuery crée un objet jqXHR pour une utilisation ultérieure, puis regroupe et envoie la requête associée. Le serveur accepte la demande, la traite, puis est prêt à répondre. Le programme serveur appellera la méthode res.json(data)à empaqueter et enverra la réponse. De retour côté client, jQuery accepte la réponse, consulte l'objet jqXHR associé et traite les données au format JSON. Tout cela fonctionne sans aucune conversion manuelle des données. La réponse n'implique aucun appel explicite à JSON.stringify () sur le serveur Node, et aucun appel explicite à JSON.parse () sur le client; tout est géré pour vous.

L'utilisation de «eval» est associée à des risques de sécurité d'injection de code. Vous pensez peut-être que cela ne peut pas arriver, mais les pirates peuvent être assez créatifs. De plus, "eval" est problématique pour l'optimisation Javascript.

Si vous utilisez une fonction "stringify ()", sachez que certaines fonctions portant ce nom créeront des chaînes compatibles avec "eval" et non avec JSON. Par exemple, dans Node, ce qui suit vous donne une fonction qui crée des chaînes au format compatible «eval»:

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

Cela peut être utile, mais sauf si vous avez un besoin spécifique, ce n'est probablement pas ce que vous voulez.


1

Si le retour d'un tableau fonctionne et le retour d'un seul objet ne fonctionne pas, vous pouvez également essayer de renvoyer votre objet unique sous forme de tableau contenant cet objet unique:

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

de cette façon, vous renvoyez une structure de données cohérente, un tableau d'objets, quelle que soit la charge utile des données.

Je vois que vous avez essayé de mettre votre objet unique entre "parenthèses", et suggérez ceci avec un exemple parce que bien sûr, JavaScript traite [..] différemment de (..)


1

Si le gestionnaire d'erreurs de jQuery est appelé et que l'objet XHR contient une "erreur d'analyseur", c'est probablement une erreur d'analyseur venant du serveur.

Votre scénario de résultats multiples est-il lorsque vous appelez le service sans paramètre, mais il est interrompu lorsque vous essayez de fournir un paramètre pour récupérer l'enregistrement unique?

De quel backend retournez-vous cela?

Sur les services ASMX, par exemple, c'est souvent le cas lorsque des paramètres sont fournis à jQuery en tant qu'objet JSON au lieu d'une chaîne JSON. Si vous fournissez à jQuery un objet JSON réel pour son paramètre "data", il le sérialisera en paires k, v standard et délimitées au lieu de l'envoyer au format JSON.


1

J'ai trouvé dans certaines de mes implémentations que je devais ajouter:

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

ce qui semblait résoudre le problème. Eval ou pas, il semblait faire exactement la même chose pour moi.


Utilisez le littéral objet lors de l'initialisation d'un nouvel objet, pas le constructeur Object: var obj = {};
Andreas Grech

Ouais je vois, var myArray = [] pour les tableaux et var myObject = {}, merci pour le conseil Dreas
Jay

1

jQuery s'étouffe sur certaines clés JSON. J'envoyais cet extrait JSON en PHP:

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

Renommer la clé «résultat» en quelque chose d'autre fonctionne. Je suppose que c'est une sorte de collision de mots réservés, et pourrait être un bogue dans jQuery (1.4.2).


1

Dans un environnement ColdFusion, une chose qui provoquera une erreur, même avec un JSON bien formé, est l' activation de l'option Activer la sortie de débogage des demandes dans l'administrateur ColdFusion (sous Débogage et journalisation> Paramètres de sortie de débogage). Les informations de débogage seront renvoyées avec les données JSON et les rendront donc invalides.


1

essayez aussi ceci

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

dans mon cas, le serveur répond avec un caractère inconnu avant '{'


1

J'obtenais status = parseerror et xhr.status = 200.

Le problème pour moi était que l'URL à l'intérieur de la réponse JSON avait résolu le problème avec le passage de «\» à «/».


0

J'avais du mal avec cela et j'ai passé quelques heures à essayer de le comprendre, jusqu'à ce que j'utilise Firebug pour afficher l'objet de données.

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

-1

utilisation

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

côté serveur. Du côté client, utilisez ajax avec Datatype JSON et assurez-vous que le codage de votre document n'est pas UTF-8 avec BOM, il doit être UTF-8.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.