Recuperar dados de um objeto ReadableStream?

135

Como posso obter informações de um ReadableStreamobjeto?

Estou usando a API de busca e não vejo isso claro na documentação.

O corpo está sendo retornado como ReadableStreame eu simplesmente gostaria de acessar uma propriedade dentro desse fluxo. Em Resposta nas ferramentas de desenvolvimento do navegador, parece que essas informações estão organizadas em propriedades, na forma de um objeto 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();
    })
novato
fonte
5
Referência API corpo
Francesco Pezzella
2
@FrancescoPezzella Obrigado pela resposta. Eu tentei response.Body.json(), mas estou recebendo itálico TypeError: Não é possível ler a propriedade 'json' de itálico indefinido . Isso ocorre porque a propriedade bodyUsed também está definida como false? No entanto, eu posso ver esse corpo na guia resposta nas ferramentas de desenvolvedor do navegador. Há uma mensagem de erro que eu gostaria de recuperar.
Noob
Portanto, seu problema está puramente relacionado à condição do erro 400? O que acontece se você alterar o manipulador para console.log(res.json());? Você vê os dados que está esperando?
Ashley 'CptLemming' Wilson
@noob Você está tentando ler a resposta como um fluxo, se res.status == 200?
guest271314
É só eu ou que a documentação é simples errado? Corrigi-o com as soluções nestas respostas.
Lucio

Respostas:

177

Para acessar os dados de um, ReadableStreamé necessário chamar um dos métodos de conversão (documentos disponíveis aqui ).

Como um exemplo:

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": "..." }
  });

EDIT: Se o seu tipo de retorno de dados não é JSON ou você não deseja JSON, usetext()

Como um exemplo:

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

Espero que isso ajude a esclarecer as coisas.

Ashley 'CptLemming' Wilson
fonte
1
Obrigado pela resposta. Eu tentei isso e ainda estou recebendo o mesmo erro em que res.body é indefinido. Eu sou capaz de recuperar o status no entanto, em primeiro lugar () função com res.status. Parece que apenas o corpo é um objeto ReadableStream. Parece ter uma propriedade bloqueada, definida como true?
Noob
Onde você está tentando acessar res.body(isso não faz parte do meu exemplo)? Você pode compartilhar algum código de exemplo na sua pergunta original para deixar mais claro onde pode estar o seu problema.
Ashley 'CptLemming' Wilson
1
Tentei acessar res.body a partir da resposta json retornada na primeira função .then (). Adicionei uma amostra à minha pergunta original para obter mais clareza. Obrigado!
Noob
1
Impressionante, usando react e request native, e imaginando o que fazer com um ReadableStream, e isso fez o truque. + +
edencorbin
Apenas um heads-up, parece um acéfalo, mas verifique se o back-end que você está atingindo está fornecendo JSON válido! Definitivamente não falando por experiência própria.
Abelito 18/04/19
44

Algumas pessoas podem achar um asyncexemplo útil:

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

json()converte o corpo da resposta de um ReadableStreamobjeto json.

As awaitinstruções devem ser agrupadas em uma asyncfunção, no entanto, você pode executar awaitinstruções diretamente no console do Chrome (a partir da versão 62).

Noel
fonte
1
Às vezes, a verdadeira resposta para você é realmente # 2 haha, faz sentido porque eles fariam .json () assíncrona, mas não foi imediatamente óbvio
Sanchit Batra
29

res.json()retorna uma promessa. Experimentar ...

res.json().then(body => console.log(body));
pinoyyid
fonte
3
Eu tentei isso, e ele imprimiu a promessa em vez do corpo.
reectrix
Tente encadear as .thenchamadas:fetch(...).then(res => res.json()).then(data => console.log(data))
Óscar Gómez Alcañiz
12

Um pouco atrasado para a festa, mas teve alguns problemas para obter algo útil de um ReadableStream solicitação de lote produzida em Odata $ usando o Sharepoint Framework.

Teve problemas semelhantes aos do OP, mas a solução no meu caso foi usar um método de conversão diferente do que .json(). No meu caso, .text()funcionou como um encanto. No entanto, foi necessário algum trabalho para obter JSON útil do arquivo de texto.

Dan Mehlqvist
fonte
2
Obrigado! Isso funcionou para mim. Estou enviando uma resposta http do Illuminate do meu servidor Laravel com um simples return $data;. Eu estava finalmente capaz de ler esta resposta no navegador comfetch(...).then(response => response.text()).then(data => console.log(data));
Cameron Hudson
10

Se você deseja apenas a resposta como texto e não deseja convertê-la em JSON, use https://developer.mozilla.org/en-US/docs/Web/API/Body/text e, em seguida then, obtenha a resposta real resultado da promessa:

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

ou

fetch('city-market.md')
  .then(function(response) {
    return response.text();
  })
  .then(function(myText) {
    console.log(myText);
  });
AlexChaffee
fonte
2

Não gosto do encadeamento de três. O segundo, então, não tem acesso ao status. Como afirmado anteriormente, 'response.json ()' retorna uma promessa. Retornando o resultado then de 'response.json ()' em um ato semelhante a um segundo então. Tem o bônus adicional de estar no escopo da resposta.

return fetch(url, params).then(response => {
    return response.json().then(body => {
        if (response.status === 200) {
            return body
        } else {
            throw body
        }
    })
})
Mardok
fonte
O encadeamento thenajuda a recuperar o valor final resolvido (the body). Aninhar eles impede que você seja capaz de obter o bodyvalor sem um retorno de chamada ou algum mecanismo do tipo. Imagine o seguinte: let body = await fetch(...).then(res => res.json()).then(data => data). Isso não funcionaria da maneira aninhada. Para verificar se há response.statussempre throwuma exceção dentro da primeira thene adicione uma catcha toda a cadeia de promessas.
Óscar Gómez Alcañiz
0

Observe que você só pode ler um fluxo uma vez; portanto, em alguns casos, pode ser necessário clonar a resposta para lê-la repetidamente:

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))
Chris Halcrow
fonte