Analyse JSON à partir de XmlHttpRequest.responseJSON

99

J'essaye d'analyser une réponse JSON bit.ly en javascript.

J'obtiens le JSON via XmlHttpRequest.

var req = new XMLHttpRequest;  
req.overrideMimeType("application/json");  
req.open('GET', BITLY_CREATE_API + encodeURIComponent(url)
          + BITLY_API_LOGIN, true);  
var target = this;  
req.onload  = function() {target.parseJSON(req, url)};  
req.send(null);

parseJSON: function(req, url) {  
if (req.status == 200) {  
    var jsonResponse = req.responseJSON;  
    var bitlyUrl = jsonResponse.results[url].shortUrl;  
}

Je fais cela dans un addon Firefox. Quand je cours, j'obtiens l'erreur "jsonResponse is undefined" pour la ligne var bitlyUrl = jsonResponse.results[url].shortUrl;. Est-ce que je fais quelque chose de mal en analysant JSON ici? Ou quel est le problème avec ce code?

chanux
la source

Réponses:

227

De nouvelles façons je: fetch

TL; DR Je recommande cette méthode tant que vous n'avez pas à envoyer de requêtes synchrones ou à prendre en charge d'anciens navigateurs.

Tant que votre requête est asynchrone, vous pouvez utiliser l' API Fetch pour envoyer des requêtes HTTP. L'API fetch fonctionne avec des promesses , ce qui est un bon moyen de gérer les flux de travail asynchrones en JavaScript. Avec cette approche, vous utilisez fetch()pour envoyer une demande et ResponseBody.json()pour analyser la réponse:

fetch(url)
  .then(function(response) {
    return response.json();
  })
  .then(function(jsonResponse) {
    // do something with jsonResponse
  });

Compatibilité: L'API Fetch n'est pas prise en charge par IE11 ni par Edge 12 et 13. Cependant, il existe des polyfills .

Nouvelles méthodes II: responseType

Comme Londeren l' a écrit dans sa réponse , les nouveaux navigateurs vous permettent d'utiliser la responseTypepropriété pour définir le format attendu de la réponse. Les données de réponse analysées sont ensuite accessibles via la responsepropriété:

var req = new XMLHttpRequest();
req.responseType = 'json';
req.open('GET', url, true);
req.onload  = function() {
   var jsonResponse = req.response;
   // do something with jsonResponse
};
req.send(null);

Compatibilité: responseType = 'json'n'est pas pris en charge par IE11.

La manière classique

Le XMLHttpRequest standard n'a pas de responseJSONpropriété, juste responseTextet responseXML. Tant que bitly répond vraiment avec du JSON à votre demande, il responseTextdoit contenir le code JSON sous forme de texte, il vous suffit donc de l'analyser avec JSON.parse():

var req = new XMLHttpRequest();
req.overrideMimeType("application/json");
req.open('GET', url, true);
req.onload  = function() {
   var jsonResponse = JSON.parse(req.responseText);
   // do something with jsonResponse
};
req.send(null);

Compatibilité: cette approche doit fonctionner avec tout navigateur prenant en charge XMLHttpRequestet JSON.

JSONHttpRequest

Si vous préférez utiliser responseJSON, mais que vous voulez une solution plus légère que JQuery, vous voudrez peut-être consulter mon JSONHttpRequest. Il fonctionne exactement comme un XMLHttpRequest normal, mais fournit également la responseJSONpropriété. Tout ce que vous avez à changer dans votre code serait la première ligne:

var req = new JSONHttpRequest();

JSONHttpRequest fournit également des fonctionnalités pour envoyer facilement des objets JavaScript au format JSON. Plus de détails et le code peuvent être trouvés ici: http://pixelsvsbytes.com/2011/12/teach-your-xmlhttprequest-some-json/ .

Divulgation complète: je suis le propriétaire de Pixels | Bytes. Je pense que mon script est une bonne solution au problème, je l'ai donc posté ici. Veuillez laisser un commentaire, si vous souhaitez que je supprime le lien.

Torben
la source
5
+1; IMO c'était la vraie réponse à la question - pas de jQuery juste de la vieille vanille XMLHttpRequest; exactement de quoi portait la question.
Fergus à Londres le
Il s a jquery version too. If you are getting crossbrowser issues essayer, généralement gérer ces problèmes framework`s mieux: api.jquery.com/jquery.parsejson
GCSCE
1
Quatre ans plus tard et cela aide encore les gens. :) Le lien vers le blog est très bien IMO, car c'est vraiment la réponse complète à la question avec un exemple de code et un téléchargement. Je vous remercie!
user1094821
"Utiliser une nouvelle bibliothèque" n'est pas aussi utile qu'on pourrait le penser.
Grunion Shaftoe
@GrunionShaftoe Pourriez-vous s'il vous plaît expliquer ce que cela signifie? Je ne suggère pas d'utiliser une nouvelle bibliothèque. Ma solution recommandée fetchest le JavaScript standard.
Torben le
25

Vous pouvez simplement définir xhr.responseType = 'json';

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://jsonplaceholder.typicode.com/posts/1');
xhr.responseType = 'json';
xhr.onload = function(e) {
  if (this.status == 200) {
    console.log('response', this.response); // JSON response  
  }
};
xhr.send();
  

Documentation pour responseType

Londeren
la source
Il y a une mise en garde majeure ici: ni IE, ni les versions actuelles d'Edge ne le prennent en charge (peut-être qu'Edge le fera finalement après la transition vers Chromium)
Machavity
3

Remarque: je n'ai testé cela que dans Chrome.

il ajoute une fonction prototype à la XMLHttpRequest .. XHR2 ,

dans XHR 1, il vous suffit probablement de le remplacer this.responseparthis.responseText

Object.defineProperty(XMLHttpRequest.prototype,'responseJSON',{value:function(){
 return JSON.parse(this.response);
},writable:false,enumerable:false});

pour retourner le json dans xhr2

xhr.onload=function(){
 console.log(this.responseJSON());
}

ÉDITER

Si vous prévoyez d'utiliser XHR avec arraybufferou d'autres types de réponse, vous devez vérifier si la réponse est un string.

dans tous les cas, vous devez ajouter plus de vérifications, par exemple s'il n'est pas capable d'analyser le json.

Object.defineProperty(XMLHttpRequest.prototype,'responseJSON',{value:function(){
 return (typeof this.response==='string'?JSON.parse(this.response):this.response);
},writable:false,enumerable:false});
cocco
la source
2
Je définirais un getter au lieu d'un attribut de fonction si j'étais vous. Remplacez simplement valuepar getdans l'objet passé à Object.defineProperty, et vous pouvez utiliser responseJSONcomme vous le feriez pour n'importe quelle autre variable de réponse.
wizzwizz4
1

Je pense que vous devez inclure jQuery pour l'utiliser responseJSON.

Sans jQuery, vous pouvez essayer avec responseText et essayer comme eval("("+req.responseText+")");

MISE À JOUR : Veuillez lire le commentaire concernant eval, vous pouvez tester avec eval, mais ne l'utilisez pas dans l'extension de travail.

OU

use json_parse : il n'utilise paseval

TU
la source
5
Pour un addon Firefox fonctionnant avec des privs de chrome, n'essayez pas d'évaluer tout ce que vous obtenez d'une source extérieure. À la place, utilisez JSON.parse (au moins dans FF 3.5 et versions ultérieures).
Ben Combee
1

Utilisez nsIJSON s'il s'agit d'une extension FF:

var req = new XMLHttpRequest;
req.overrideMimeType("application/json");
req.open('GET', BITLY_CREATE_API + encodeURIComponent(url) + BITLY_API_LOGIN, true);
var target = this;
req.onload = function() {target.parseJSON(req, url)};
req.send(null);

parseJSON: function(req, url) {
if (req.status == 200) {
  var jsonResponse = Components.classes["@mozilla.org/dom/json;1"]
      .createInstance(Components.interfaces.nsIJSON.decode(req.responseText);
  var bitlyUrl = jsonResponse.results[url].shortUrl;
}

Pour une page Web, utilisez simplement à la JSON.parseplace deComponents.classes["@mozilla.org/dom/json;1"].createInstance(Components.interfaces.nsIJSON.decode

Erikvold
la source