Analisando JSON de XmlHttpRequest.responseJSON

99

Estou tentando analisar uma resposta JSON bit.ly em javascript.

Eu obtenho o 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;  
}

Eu faço isso em um addon do firefox. Quando eu executo, obtenho o erro "jsonResponse is undefined" para a linha var bitlyUrl = jsonResponse.results[url].shortUrl;. Estou fazendo algo errado ao analisar JSON aqui? Ou o que há de errado com este código?

Chanux
fonte

Respostas:

227

Novas maneiras I: fetch

TL; DR Eu recomendo essa forma, desde que você não precise enviar solicitações síncronas ou oferecer suporte a navegadores antigos.

Contanto que sua solicitação seja assíncrona, você pode usar a API Fetch para enviar solicitações HTTP. A API fetch funciona com promessas , que é uma boa maneira de lidar com fluxos de trabalho assíncronos em JavaScript. Com essa abordagem, você usa fetch()para enviar uma solicitação e ResponseBody.json()analisar a resposta:

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

Compatibilidade: A API Fetch não é compatível com o IE11 e também com o Edge 12 e 13. No entanto, existem polyfills .

Novas maneiras II: responseType

Como Londeren escreveu em sua resposta , os navegadores mais recentes permitem que você use a responseTypepropriedade para definir o formato esperado da resposta. Os dados de resposta analisados ​​podem ser acessados ​​por meio da responsepropriedade:

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

Compatibilidade: responseType = 'json'não é compatível com o IE11.

O jeito clássico

O XMLHttpRequest padrão não possui responseJSONpropriedade, apenas responseTexte responseXML. Contanto que o bitly realmente responda com algum JSON à sua solicitação, responseTextdeve conter o código JSON como texto, então tudo que você precisa fazer é analisá-lo com 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);

Compatibilidade: esta abordagem deve funcionar com qualquer navegador que suporte XMLHttpRequeste JSON.

JSONHttpRequest

Se você preferir usar responseJSON, mas deseja uma solução mais leve do que JQuery, você pode querer verificar meu JSONHttpRequest. Ele funciona exatamente como um XMLHttpRequest normal, mas também fornece a responseJSONpropriedade. Tudo que você precisa alterar em seu código é a primeira linha:

var req = new JSONHttpRequest();

JSONHttpRequest também fornece funcionalidade para enviar facilmente objetos JavaScript como JSON. Mais detalhes e o código podem ser encontrados aqui: http://pixelsvsbytes.com/2011/12/teach-your-xmlhttprequest-some-json/ .

Divulgação completa: Sou o dono da Pixels | Bytes. Acho que meu script é uma boa solução para o problema, então o postei aqui. Por favor, deixe um comentário, se você quiser que eu remova o link.

Torben
fonte
5
+1; IMO, esta foi a verdadeira resposta para a pergunta - não jQuery, simplesmente baunilha velha XMLHttpRequest; exatamente sobre o que era a pergunta.
Fergus In London
Não s a jquery version too. If you are getting crossbrowser issueé experimentá-lo, geralmente framework`s lidar com estes problemas melhor: api.jquery.com/jquery.parsejson
sagits
1
Quatro anos depois e isso ainda está ajudando as pessoas. :) O link para o blog é bom IMO, já que realmente é a resposta completa para a pergunta com código de amostra e um download. Obrigado!
user1094821
"Usar uma nova biblioteca" não é tão útil quanto se possa pensar.
Grunion Shaftoe
@GrunionShaftoe Você poderia explicar, o que significa? Não estou sugerindo o uso de uma nova biblioteca. Minha solução recomendada fetché JavaScript padrão.
Torben
25

Você pode simplesmente definir 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();
  

Documentação para responseType

Londeren
fonte
Há uma grande advertência aqui: nem o IE, nem as versões atuais do Edge suportam isso (talvez o Edge finalmente o suporte após a transição para o Chromium)
Machavity
3

Nota: Eu só testei isso no Chrome.

adiciona uma função de protótipo ao XMLHttpRequest .. XHR2 ,

em XHR 1, você provavelmente só precisa substituir this.responseporthis.responseText

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

para retornar o json em xhr2

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

EDITAR

Se você planeja usar XHR com arraybufferou outros tipos de resposta, você deve verificar se a resposta é umstring .

em qualquer caso, você deve adicionar mais verificações, por exemplo, se não for capaz de analisar o json.

Object.defineProperty(XMLHttpRequest.prototype,'responseJSON',{value:function(){
 return (typeof this.response==='string'?JSON.parse(this.response):this.response);
},writable:false,enumerable:false});
cocco
fonte
2
Eu definiria um getter em vez de um atributo de função se eu fosse você. Basta substituir valuepor getno objeto passado paraObject.defineProperty , e você pode usar responseJSONcomo faria com qualquer outra variável de resposta.
wizzwizz4
1

Acho que você tem que incluir o jQuery para usar responseJSON.

Sem jQuery, você pode tentar com responseText e tentar como eval("("+req.responseText+")");

ATUALIZAÇÃO : Por favor, leia o comentário a respeito eval, você pode testar com eval, mas não use em uma extensão funcional.

OU

use json_parse : não usaeval

VOCÊS
fonte
5
Para um complemento do Firefox rodando com privs do Chrome, não tente avaliar nada que você obtenha de uma fonte externa. Em vez disso, use JSON.parse (pelo menos no FF 3.5 e posterior).
Ben Combee
1

Use nsIJSON se for para uma extensão 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;
}

Para uma página da web, basta usar em JSON.parsevez deComponents.classes["@mozilla.org/dom/json;1"].createInstance(Components.interfaces.nsIJSON.decode

Erikvold
fonte