Разбор JSON из XmlHttpRequest.responseJSON

101

Я пытаюсь немного разобрать ответ JSON в javascript.

Я получаю JSON через 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;  
}

Я делаю это в аддоне firefox. При запуске я получаю сообщение об ошибке «jsonResponse is undefined» для строки var bitlyUrl = jsonResponse.results[url].shortUrl;. Я здесь что-то не так делаю, разбирая JSON? Или что не так с этим кодом?

Chanux
источник

Ответы:

229

Новые способы I: fetch

TL; DR Я бы рекомендовал этот способ, если вам не нужно отправлять синхронные запросы или поддерживать старые браузеры.

Если ваш запрос является асинхронным, вы можете использовать Fetch API для отправки HTTP-запросов. API-интерфейс fetch работает с обещаниями , что является хорошим способом обработки асинхронных рабочих процессов в JavaScript. При таком подходе вы используете fetch()для отправки запроса и ResponseBody.json()анализа ответа:

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

Совместимость: Fetch API не поддерживается IE11, а также Edge 12 и 13. Однако есть полифилы .

Новые способы II: responseType

Как написал Лондерен в своем ответе , новые браузеры позволяют использовать responseTypeсвойство для определения ожидаемого формата ответа. Затем к проанализированным данным ответа можно получить доступ через responseсвойство:

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

Совместимость: responseType = 'json'не поддерживается IE11.

Классический способ

Стандартный XMLHttpRequest не имеет responseJSONсвойства, только responseTextи responseXML. Пока bitly действительно отвечает некоторым JSON на ваш запрос, он responseTextдолжен содержать код JSON в виде текста, поэтому все, что вам нужно сделать, это проанализировать его с помощью 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);

Совместимость: этот подход должен работать с любым браузером, который поддерживает XMLHttpRequestи JSON.

JSONHttpRequest

Если вы предпочитаете использовать responseJSON, но хотите более легкое решение, чем JQuery, вы можете проверить мой JSONHttpRequest. Он работает точно так же, как обычный XMLHttpRequest, но также предоставляет responseJSONсвойство. Все, что вам нужно изменить в своем коде, это первая строка:

var req = new JSONHttpRequest();

JSONHttpRequest также предоставляет функциональные возможности для простой отправки объектов JavaScript в формате JSON. Более подробную информацию и код можно найти здесь: http://pixelsvsbytes.com/2011/12/teach-your-xmlhttprequest-some-json/ .

Полное раскрытие: я владелец Pixels | Bytes. Думаю, мой сценарий - хорошее решение проблемы, поэтому разместил его здесь. Пожалуйста, оставьте комментарий, если хотите, чтобы я удалил ссылку.

Торбен
источник
5
+1; ИМО, это был реальный ответ на вопрос - нет jQuery, просто старая ваниль XMLHttpRequest; о чем был вопрос.
Фергус в Лондоне
Там s a jquery version too. If you are getting crossbrowser issueпопробуем это, как правило , framework`s справиться с этими проблемами лучше: api.jquery.com/jquery.parsejson
sagits
1
Четыре года спустя, и это все еще помогает людям. :) Ссылка на блог - это нормально, ИМО, так как это действительно полный ответ на вопрос с образцом кода и загрузкой. Спасибо!
user1094821
«Использовать новую библиотеку» не так полезно, как можно было бы подумать.
Грунион Шафто
@GrunionShaftoe Не могли бы вы объяснить, что значит? Я не предлагаю использовать новую библиотеку. Мое рекомендуемое решение fetch- стандартный JavaScript.
Торбен
25

Вы можете просто установить 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();
  

Документация для responseType

Лондерен
источник
Здесь есть серьезная оговорка: ни IE, ни текущие версии Edge не поддерживают это (возможно, Edge наконец-то появится после перехода на Chromium)
Machavity
3

Примечание. Я тестировал это только в Chrome.

он добавляет функцию-прототип к XMLHttpRequest .. XHR2 ,

в XHR 1 вам, вероятно, просто нужно заменить this.responseнаthis.responseText

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

чтобы вернуть json в xhr2

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

РЕДАКТИРОВАТЬ

Если вы планируете использовать XHR с arraybufferили другими типами ответов, вам необходимо проверить, является ли ответ string.

в любом случае вам нужно добавить больше проверок, например, если он не может проанализировать json.

Object.defineProperty(XMLHttpRequest.prototype,'responseJSON',{value:function(){
 return (typeof this.response==='string'?JSON.parse(this.response):this.response);
},writable:false,enumerable:false});
кокко
источник
2
На вашем месте я бы определил геттер вместо атрибута функции. Просто замените valueс getв объекте передается Object.defineProperty, и вы можете использовать , responseJSONкак и любой другой переменной отклика.
wizzwizz4
1

Я думаю, вам нужно включить jQuery для использования responseJSON.

Без jQuery вы можете попробовать responseText и попробовать eval("("+req.responseText+")");

ОБНОВЛЕНИЕ : прочтите комментарий о том eval, что вы можете тестировать с помощью eval, но не используйте его в рабочем расширении.

ИЛИ

используйте json_parse : он не используетeval

ТЫ
источник
5
Для надстройки Firefox, работающей с привилегиями chrome, не пытайтесь оценивать все, что вы получаете из внешнего источника. Вместо этого используйте JSON.parse (по крайней мере, в FF 3.5 и новее).
Бен Комби,
1

Используйте nsIJSON, если это для расширения 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;
}

Для веб-страницы просто используйте JSON.parseвместоComponents.classes["@mozilla.org/dom/json;1"].createInstance(Components.interfaces.nsIJSON.decode

Эриквольд
источник