Analizowanie JSON z XmlHttpRequest.responseJSON

100

Próbuję przeanalizować odpowiedź JSON bit.ly w javascript.

Otrzymuję JSON przez 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;  
}

Robię to w dodatku do Firefoksa. Po uruchomieniu pojawia się błąd „jsonResponse is undefined” dla linii var bitlyUrl = jsonResponse.results[url].shortUrl;. Czy robię coś złego podczas analizowania JSON tutaj? Albo co jest nie tak z tym kodem?

chanux
źródło

Odpowiedzi:

228

Nowe sposoby: fetch

TL; DR polecałbym ten sposób, o ile nie musisz wysyłać synchronicznych żądań ani obsługiwać starych przeglądarek.

Dopóki żądanie jest asynchroniczne, możesz używać interfejsu Fetch API do wysyłania żądań HTTP. Fetch API działa z obietnicami , co jest dobrym sposobem obsługi asynchronicznych przepływów pracy w JavaScript. W tym podejściu używasz fetch()do wysyłania żądania i ResponseBody.json()analizowania odpowiedzi:

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

Zgodność: Fetch API nie jest obsługiwany przez IE11 oraz Edge 12 i 13. Istnieją jednak polyfills .

Nowe sposoby II: responseType

Jak napisał Londeren w swojej odpowiedzi , nowsze przeglądarki pozwalają na użycie tej responseTypewłaściwości do zdefiniowania oczekiwanego formatu odpowiedzi. Następnie można uzyskać dostęp do przeanalizowanych danych odpowiedzi za pośrednictwem responsewłaściwości:

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

Zgodność: responseType = 'json'nie jest obsługiwana przez IE11.

Klasyczny sposób

Standardowy XMLHttpRequest nie ma responseJSONwłaściwości, tylko responseTexti responseXML. Tak długo, jak bitly naprawdę odpowiada jakimś responseTextkodem JSON na Twoje żądanie, powinien zawierać kod JSON jako tekst, więc wszystko, co musisz zrobić, to przeanalizować go za pomocą 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);

Zgodność: to podejście powinno działać z każdą przeglądarką obsługującą XMLHttpRequesti JSON.

JSONHttpRequest

Jeśli wolisz używać responseJSON, ale chcesz lżejszego rozwiązania niż JQuery, możesz sprawdzić mój JSONHttpRequest. Działa dokładnie tak, jak zwykły XMLHttpRequest, ale zapewnia również tę responseJSONwłaściwość. Wszystko, co musisz zmienić w swoim kodzie, to pierwsza linia:

var req = new JSONHttpRequest();

JSONHttpRequest zapewnia również funkcjonalność umożliwiającą łatwe wysyłanie obiektów JavaScript jako JSON. Więcej szczegółów i kod można znaleźć tutaj: http://pixelsvsbytes.com/2011/12/teach-your-xmlhttprequest-some-json/ .

Pełne ujawnienie: jestem właścicielem Pixels | Bytes. Myślę, że mój skrypt jest dobrym rozwiązaniem problemu, więc zamieściłem go tutaj. Proszę zostaw komentarz, jeśli chcesz, żebym usunął link.

Torben
źródło
5
+1; IMO to była prawdziwa odpowiedź na pytanie - bez jQuery, tylko zwykła stara wanilia XMLHttpRequest; właśnie o co chodziło w tym pytaniu.
Fergus w Londynie,
Nie s a jquery version too. If you are getting crossbrowser issues spróbować, zwykle framework`s rozwiązania tych problemów lepiej: api.jquery.com/jquery.parsejson
sagits
1
Cztery lata później i to nadal pomaga ludziom. :) Linkowanie do bloga jest w porządku IMO, ponieważ tak naprawdę jest to pełna odpowiedź na pytanie z przykładowym kodem i plikiem do pobrania. Dziękuję Ci!
user1094821
„Użyj nowej biblioteki” nie jest tak pomocne, jak mogłoby się wydawać.
Grunion Shaftoe
@GrunionShaftoe Czy mógłbyś wyjaśnić, co to znaczy? Nie proponuję używania nowej biblioteki. Moje zalecane rozwiązaniefetch jest standardowy JavaScript.
Torben
25

Możesz po prostu ustawić 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();
  

Dokumentacja typu responseType

Londeren
źródło
Jest tu poważne zastrzeżenie: ani IE, ani obecne wersje Edge nie obsługują tego (być może Edge w końcu to zrobi po przejściu na Chromium)
Machavity
3

Uwaga: przetestowałem to tylko w Chrome.

dodaje funkcję prototypową do XMLHttpRequest .. XHR2 ,

w XHR 1 prawdopodobnie wystarczy wymienić this.responsezthis.responseText

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

aby zwrócić plik json w xhr2

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

EDYTOWAĆ

Jeśli planujesz używać XHR z arraybufferinnymi typami odpowiedzi, musisz sprawdzić, czy odpowiedź to string.

w każdym razie musisz dodać więcej sprawdzeń, np. jeśli nie jest w stanie przeanalizować json.

Object.defineProperty(XMLHttpRequest.prototype,'responseJSON',{value:function(){
 return (typeof this.response==='string'?JSON.parse(this.response):this.response);
},writable:false,enumerable:false});
cocco
źródło
2
Na twoim miejscu zdefiniowałbym getter zamiast atrybutu funkcji. Wystarczy wymienić valueze getw obiekcie przekazanym Object.defineProperty, i można go używać responseJSONjak każdy inny zmiennej odpowiedzi.
wizzwizz4
1

Myślę, że musisz dołączyć jQuery do użycia responseJSON.

Bez jQuery możesz spróbować z responseText i polubić eval("("+req.responseText+")");

AKTUALIZACJA : Przeczytaj komentarz dotyczący eval, możesz testować z eval, ale nie używaj go w działającym rozszerzeniu.

LUB

użyj json_parse : nie używaeval

TY
źródło
5
W przypadku dodatku do Firefoksa działającego z uprawnieniami Chrome nie próbuj oceniać niczego, co otrzymujesz z zewnętrznego źródła. Zamiast tego użyj JSON.parse (przynajmniej w FF 3.5 i nowszych).
Ben Combee
1

Użyj nsIJSON, jeśli jest to rozszerzenie 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;
}

W przypadku strony internetowej po prostu użyj JSON.parsezamiastComponents.classes["@mozilla.org/dom/json;1"].createInstance(Components.interfaces.nsIJSON.decode

erikvold
źródło