Получить данные из объекта ReadableStream?

136

Как я могу получить информацию от ReadableStreamобъекта?

Я использую Fetch API и не вижу, чтобы это было ясно из документации.

Тело возвращается как объект, ReadableStreamи я просто хотел бы получить доступ к свойству в этом потоке. В разделе «Ответ» в инструментах разработчика браузера я, кажется, организовал эту информацию в свойствах в форме объекта JavaScript.

fetch('http://192.168.5.6:2000/api/car', obj)
    .then((res) => {
        if(res.status == 200) {
            console.log("Success :" + res.statusText);   //works just fine
        }
        else if(res.status == 400) {
            console.log(JSON.stringify(res.body.json());  //res.body is undefined.
        }

        return res.json();
    })
новичек
источник
5
Справка Body API
Francesco Pezzella
2
@FrancescoPezzella Спасибо за ответ. Я пробовал response.Body.json(), но получаю курсив TypeError: невозможно прочитать свойство json с неопределенным курсивом . Это потому, что для свойства bodyUsed также установлено значение false? Однако я могу просмотреть это тело на вкладке ответа в инструментах разработчика браузера. Появляется сообщение об ошибке, которое я хотел бы получить.
noob
Итак, ваша проблема связана исключительно с ошибкой 400? Что произойдет, если вы измените обработчик на console.log(res.json());? Вы видите ожидаемые данные?
Эшли 'CptLemming' Уилсон
@noob Вы пытаетесь прочитать ответ как поток, если res.status == 200?
guest271314
Это только я или эта документация явно неверна? Я исправил это с помощью решений по этим ответам.
Lucio

Ответы:

178

Чтобы получить доступ к данным из файла, ReadableStreamвам необходимо вызвать один из методов преобразования (документы доступны здесь ).

Например:

fetch('https://jsonplaceholder.typicode.com/posts/1')
  .then(function(response) {
    // The response is a Response instance.
    // You parse the data into a useable format using `.json()`
    return response.json();
  }).then(function(data) {
    // `data` is the parsed version of the JSON returned from the above endpoint.
    console.log(data);  // { "userId": 1, "id": 1, "title": "...", "body": "..." }
  });

РЕДАКТИРОВАТЬ: если ваш тип возвращаемых данных не JSON или вы не хотите JSON, используйтеtext()

Например:

fetch('https://jsonplaceholder.typicode.com/posts/1')
  .then(function(response) {
    return response.text();
  }).then(function(data) {
    console.log(data); // this will be a string
  });

Надеюсь, это поможет прояснить ситуацию.

Эшли 'CptLemming' Уилсон
источник
1
Спасибо за ответ. Я пробовал это и все еще получаю ту же ошибку, когда res.body не определен. Однако я могу получить статус сначала в функции then () с res.status. Кажется, что объектом ReadableStream является только тело. Кажется, что свойство заблокировано, для которого установлено значение true?
noob
Куда вы пытаетесь получить доступ res.body(это не часть моего примера)? Не могли бы вы поделиться образцом кода в исходном вопросе, чтобы было понятнее, где может быть ваша проблема.
Эшли 'CptLemming' Уилсон
1
Я попытался получить доступ к res.body из ответа json, который был возвращен в первой функции .then (). Я добавил образец к своему исходному вопросу для большей ясности. Спасибо!
noob
1
Потрясающе, используя реагирование и нативные запросы, и задаваясь вопросом, что вообще делать с ReadableStream, и это помогло. ++
edencorbin
Просто напомню, что кажется несложным, но убедитесь, что сервер, на который вы обращаетесь, действительно предоставляет действительный JSON! Определенно не по опыту.
abelito
45

Некоторым может asyncпригодиться пример:

var response = await fetch("https://httpbin.org/ip");
var body = await response.json(); // .json() is asynchronous and therefore must be awaited

json()преобразует тело ответа из объекта ReadableStreamjson.

Эти awaitзаявления должны быть завернуты в asyncфункции, однако вы можете запустить awaitзаявления непосредственно в консоли Chrome (в версии 62).

Ноэль
источник
1
Иногда настоящий ответ для вас - №2, ха-ха, имеет смысл, почему они сделали .json () асинхронным, но это было не сразу очевидно
Санчит Батра
29

res.json()возвращает обещание. Пытаться ...

res.json().then(body => console.log(body));
pinoyyid
источник
3
Я попробовал это, и он распечатал обещание вместо тела.
reectrix
Попробуйте .thenfetch(...).then(res => res.json()).then(data => console.log(data))
Оскар Гомес Альканьис
12

Немного опоздал на вечеринку, но возникли проблемы с получением чего-то полезного из ReadableStreamпакетного запроса, созданного с помощью Odata $, с использованием Sharepoint Framework.

Были проблемы, аналогичные OP, но решение в моем случае заключалось в использовании другого метода преобразования, чем .json(). В моем случае .text()сработало как шарм. Однако, чтобы получить полезный JSON из текстового файла, потребовалось немного возиться.

Дэн Мелквист
источник
2
Спасибо! Это сработало для меня. Я отправляю HTTP-ответ Illuminate с моего сервера Laravel с простым return $data;. Я наконец смог прочитать этот ответ в браузере сfetch(...).then(response => response.text()).then(data => console.log(data));
Кэмерон Хадсон
10

Если вы просто хотите получить ответ в виде текста и не хотите преобразовывать его в JSON, используйте https://developer.mozilla.org/en-US/docs/Web/API/Body/text, а затем thenего, чтобы получить фактический результат обещания:

fetch('city-market.md')
  .then(function(response) {
    response.text().then((s) => console.log(s));
  });

или

fetch('city-market.md')
  .then(function(response) {
    return response.text();
  })
  .then(function(myText) {
    console.log(myText);
  });
AlexChaffee
источник
2

Мне не нравятся цепочки. Второй тогда не имеет доступа к статусу. Как было сказано ранее, response.json () возвращает обещание. Возврат тогда результата response.json () в a действует аналогично секунде then. У него есть дополнительный бонус, заключающийся в том, что он находится в рамках ответа.

return fetch(url, params).then(response => {
    return response.json().then(body => {
        if (response.status === 200) {
            return body
        } else {
            throw body
        }
    })
})
Mardok
источник
Цепочка thenпомогает вам получить окончательное разрешенное значение ( body). Их вложение не дает вам получить bodyзначение без обратного вызова или какого-либо механизма подобного рода. Представьте себе , это: let body = await fetch(...).then(res => res.json()).then(data => data). Это не будет работать вложенным способом. Чтобы проверить, response.statusвы всегда можете throwсоздать исключение внутри первого thenи добавить catchко всей цепочке обещаний.
Оскар Гомес Альканьис
0

Обратите внимание, что вы можете прочитать поток только один раз, поэтому в некоторых случаях вам может потребоваться клонировать ответ, чтобы повторно читать его:

fetch('example.json')
  .then(res=>res.clone().json())
  .then( json => console.log(json))

fetch('url_that_returns_text')
  .then(res=>res.clone().text())
  .then( text => console.log(text))
Крис Хэлкроу
источник