Analisi di JSON da XmlHttpRequest.responseJSON


99

Sto cercando di analizzare una risposta JSON bit.ly in javascript.

Ottengo il JSON tramite 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;  
}

Lo faccio in un addon per Firefox. Quando eseguo ricevo l'errore "jsonResponse is undefined" per la riga var bitlyUrl = jsonResponse.results[url].shortUrl;. Sto facendo qualcosa di sbagliato nell'analisi di JSON qui? O cosa c'è di sbagliato in questo codice?

Risposte:


227

Nuovi modi io: fetch

TL; DR Suggerirei in questo modo purché non sia necessario inviare richieste sincrone o supportare vecchi browser.

Finché la tua richiesta è asincrona, puoi utilizzare l' API Fetch per inviare richieste HTTP. L'API fetch funziona con le promesse , che è un bel modo per gestire flussi di lavoro asincroni in JavaScript. Con questo approccio si utilizza fetch()per inviare una richiesta e ResponseBody.json()per analizzare la risposta:

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

Compatibilità: l'API Fetch non è supportata da IE11 e da Edge 12 e 13. Tuttavia, sono presenti polyfill .

Nuovi modi II: responseType

Come ha scritto Londeren nella sua risposta , i browser più recenti consentono di utilizzare la responseTypeproprietà per definire il formato previsto della risposta. È quindi possibile accedere ai dati di risposta analizzati tramite la responseproprietà:

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'non è supportato da IE11.

Il modo classico

Lo standard XMLHttpRequest non ha responseJSONproprietà, solo responseTexte responseXML. Finché bitly risponde davvero con un po 'di JSON alla tua richiesta, responseTextdovrebbe contenere il codice JSON come testo, quindi tutto ciò che devi fare è analizzarlo con 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à: questo approccio dovrebbe funzionare con qualsiasi browser che supporti XMLHttpRequeste JSON.

JSONHttpRequest

Se preferisci usare responseJSON, ma desideri una soluzione più leggera di JQuery, potresti voler controllare il mio JSONHttpRequest. Funziona esattamente come un normale XMLHttpRequest, ma fornisce anche la responseJSONproprietà. Tutto quello che devi cambiare nel tuo codice sarebbe la prima riga:

var req = new JSONHttpRequest();

JSONHttpRequest fornisce anche funzionalità per inviare facilmente oggetti JavaScript come JSON. Maggiori dettagli e il codice possono essere trovati qui: http://pixelsvsbytes.com/2011/12/teach-your-xmlhttprequest-some-json/ .

Divulgazione completa: sono il proprietario di Pixel | Bytes. Penso che il mio script sia una buona soluzione al problema, quindi l'ho pubblicato qui. Per favore lascia un commento, se vuoi che rimuova il link.


5
+1; IMO questa era la vera risposta alla domanda - niente jQuery solo semplice vecchia vaniglia XMLHttpRequest; proprio di cosa si trattava.
Fergus a Londra l'

Ci s a jquery version too. If you are getting crossbrowser issues provare, di solito framework`s gestire questi problemi meglio: api.jquery.com/jquery.parsejson
sagits

1
Quattro anni dopo e questo aiuta ancora le persone. :) Il collegamento al blog va bene IMO, poiché è davvero la risposta completa alla domanda con codice di esempio e un download. Grazie!
user1094821

"Usa una nuova libreria" non è così utile come si potrebbe pensare.
Grunion Shaftoe

@GrunionShaftoe Potresti spiegare, cosa significa? Non sto suggerendo di utilizzare una nuova libreria. La mia soluzione consigliata fetchè JavaScript standard.
Torben,

25

Puoi semplicemente impostare 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();
  

Documentazione per responseType


C'è un avvertimento importante qui: né IE, né le versioni attuali di Edge lo supportano (forse Edge lo farà finalmente dopo la transizione a Chromium)
Machavity

3

Nota: l'ho testato solo in Chrome.

aggiunge una funzione prototipo a XMLHttpRequest .. XHR2 ,

in XHR 1 probabilmente devi solo sostituire this.responseconthis.responseText

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

per restituire il json in xhr2

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

MODIFICARE

Se si prevede di utilizzare XHR con arraybuffero altri tipi di risposta, è necessario verificare se la risposta è un file string.

in ogni caso devi aggiungere più controlli ad esempio se non è in grado di analizzare il json.

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

2
Definirei un getter invece di un attributo di funzione se fossi in te. Basta sostituire valuecon getnell'oggetto passato a Object.defineProperty, e puoi usare responseJSONcome faresti con qualsiasi altra variabile di risposta.
wizzwizz4

1

Penso che tu debba includere jQuery da usare responseJSON.

Senza jQuery, potresti provare con responseText e provare come eval("("+req.responseText+")");

AGGIORNAMENTO : Si prega di leggere il commento in merito eval, è possibile testare con eval, ma non utilizzarlo nell'estensione di lavoro.

O

usa json_parse : non usaeval


5
Per un componente aggiuntivo di Firefox in esecuzione con chrome privs, non provare a valutare tutto ciò che ottieni da una fonte esterna. Utilizza invece JSON.parse (almeno in FF 3.5 e versioni successive).
Ben Combee

1

Usa nsIJSON se questo è per un'estensione 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;
}

Per una pagina web, usa semplicemente JSON.parseinvece diComponents.classes["@mozilla.org/dom/json;1"].createInstance(Components.interfaces.nsIJSON.decode

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.