Analizando JSON desde XmlHttpRequest.responseJSON

99

Estoy tratando de analizar una respuesta JSON bit.ly en javascript.

Obtengo el JSON a través de 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;  
}

Hago esto en un complemento de Firefox. Cuando ejecuto, aparece el error "jsonResponse is undefined" para la línea var bitlyUrl = jsonResponse.results[url].shortUrl;. ¿Estoy haciendo algo mal al analizar JSON aquí? ¿O qué hay de malo en este código?

chanux
fuente

Respuestas:

227

Nuevas formas yo: fetch

TL; DR Recomendaría de esta manera siempre que no tenga que enviar solicitudes sincrónicas o admitir navegadores antiguos.

Siempre que su solicitud sea asíncrona, puede utilizar la API Fetch para enviar solicitudes HTTP. La API de recuperación funciona con promesas , que es una buena forma de manejar flujos de trabajo asincrónicos en JavaScript. Con este enfoque se utiliza fetch()para enviar una solicitud y ResponseBody.json()analizar la respuesta:

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

Compatibilidad: la API Fetch no es compatible con IE11 ni con Edge 12 y 13. Sin embargo, existen polyfills .

Nuevas formas II: responseType

Como Londeren ha escrito en su respuesta , los navegadores más nuevos le permiten usar la responseTypepropiedad para definir el formato esperado de la respuesta. A continuación, se puede acceder a los datos de respuesta analizados a través de la responsepropiedad:

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

Compatibilidad: responseType = 'json'no es compatible con IE11.

La forma clásica

El XMLHttpRequest estándar no tiene responseJSONpropiedad, solo responseTexty responseXML. Siempre que bitly realmente responda con algo de JSON a su solicitud, responseTextdebe contener el código JSON como texto, por lo que todo lo que tiene que hacer es analizarlo 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);

Compatibilidad: este enfoque debería funcionar con cualquier navegador que admita XMLHttpRequesty JSON.

JSONHttpRequest

Si prefiere usar responseJSON, pero desea una solución más liviana que JQuery, es posible que desee consultar mi JSONHttpRequest. Funciona exactamente como una XMLHttpRequest normal, pero también proporciona la responseJSONpropiedad. Todo lo que tiene que cambiar en su código sería la primera línea:

var req = new JSONHttpRequest();

JSONHttpRequest también proporciona funcionalidad para enviar fácilmente objetos JavaScript como JSON. Puede encontrar más detalles y el código aquí: http://pixelsvsbytes.com/2011/12/teach-your-xmlhttprequest-some-json/ .

Divulgación completa: soy el propietario de Pixels | Bytes. Creo que mi guión es una buena solución al problema, así que lo publiqué aquí. Deje un comentario si desea que elimine el enlace.

Torben
fuente
5
+1; En mi opinión, esta fue la respuesta real a la pregunta: no jQuery, simplemente vainilla vieja XMLHttpRequest; de qué trataba la pregunta.
Fergus en Londres
No s a jquery version too. If you are getting crossbrowser issues probarlo, por lo general manejar estos problemas framework`s mejor: api.jquery.com/jquery.parsejson
SAGIT
1
Cuatro años después y esto sigue ayudando a la gente. :) La vinculación al blog está bien en mi opinión, ya que realmente es la respuesta completa a la pregunta con un código de muestra y una descarga. ¡Gracias!
user1094821
"Utilizar una nueva biblioteca" no es tan útil como podría pensarse.
Grunion Shaftoe
@GrunionShaftoe ¿Podría explicar, por favor, qué significa? No estoy sugiriendo usar una nueva biblioteca. Mi solución recomendada fetches JavaScript estándar.
Torben
25

Simplemente puede configurar 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();
  

Documentación para responseType

Londeren
fuente
Aquí hay una advertencia importante: ni IE ni las versiones actuales de Edge admiten esto (tal vez Edge finalmente lo haga después de la transición a Chromium)
Machavity
3

Nota: Solo he probado esto en Chrome.

agrega una función de prototipo a XMLHttpRequest .. XHR2 ,

en XHR 1 probablemente solo necesite reemplazar this.responseconthis.responseText

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

para devolver el json en xhr2

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

EDITAR

Si planea usar XHR con arraybuffer u otros tipos de respuesta, debe verificar si la respuesta es un string.

en cualquier caso, debe agregar más controles, por ejemplo, si no puede analizar el json.

Object.defineProperty(XMLHttpRequest.prototype,'responseJSON',{value:function(){
 return (typeof this.response==='string'?JSON.parse(this.response):this.response);
},writable:false,enumerable:false});
coco
fuente
2
Definiría un getter en lugar de un atributo de función si fuera usted. Simplemente reemplace valuecon geten el objeto pasado a Object.defineProperty, y puede usarlo responseJSONcomo lo haría con cualquier otra variable de respuesta.
wizzwizz4
1

Creo que tienes que incluir jQuery para usar responseJSON.

Sin jQuery, podrías probar con responseText y probar como eval("("+req.responseText+")");

ACTUALIZACIÓN : lea el comentario sobre eval, puede probar con eval, pero no lo use en la extensión de trabajo.

O

use json_parse : no usaeval


fuente
5
Para un complemento de Firefox que se ejecuta con Chrome privs, no intente evaluar nada que obtenga de una fuente externa. En su lugar, use JSON.parse (al menos en FF 3.5 y posterior).
Ben Combee
1

Use nsIJSON si esto es para una extensión 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 una página web, solo use en JSON.parselugar deComponents.classes["@mozilla.org/dom/json;1"].createInstance(Components.interfaces.nsIJSON.decode

erikvold
fuente