¿Recuperar datos de un objeto ReadableStream?

135

¿Cómo puedo obtener información de un ReadableStreamobjeto?

Estoy usando la API Fetch y no veo que esto esté claro en la documentación.

El cuerpo se devuelve como ReadableStreamay simplemente me gustaría acceder a una propiedad dentro de esta secuencia. En Respuesta en las herramientas de desarrollo del navegador, parece que tengo esta información organizada en propiedades, en forma de un 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
fuente
55
Referencia de la API del cuerpo
Francesco Pezzella, el
2
@FrancescoPezzella Gracias por la respuesta. Lo he intentado response.Body.json(), pero me está apareciendo TypeError en cursiva : no se puede leer la propiedad 'json' de cursiva indefinida . ¿Es esto porque la propiedad bodyUsed también se establece en falso? Sin embargo, puedo ver este cuerpo en la pestaña de respuesta en las herramientas de desarrollo del navegador. Hay un mensaje de error que me gustaría recuperar.
novato
¿Entonces su problema está puramente relacionado con la condición de error 400? ¿Qué sucede si cambia el controlador a console.log(res.json());? ¿Ves los datos que esperas?
Ashley 'CptLemming' Wilson
@noob ¿Estás intentando leer la respuesta como una transmisión si res.status == 200?
invitado271314
¿Soy solo yo o esa documentación es simplemente errónea? Sin embargo, lo solucioné con las soluciones de estas respuestas.
Lucio

Respuestas:

177

Para acceder a los datos desde un ReadableStreamdebe llamar a uno de los métodos de conversión (documentos disponibles aquí ).

Como ejemplo:

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

EDITAR: si su tipo de retorno de datos no es JSON o no desea JSON, usetext()

Como ejemplo:

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 esto ayude a aclarar las cosas.

Ashley 'CptLemming' Wilson
fuente
1
Gracias por la respuesta. He intentado esto y sigo recibiendo el mismo error donde res.body no está definido. Sin embargo, puedo recuperar el estado primero en la función () con res.status. Parece que solo el cuerpo es un objeto ReadableStream. ¿Parece tener una propiedad bloqueada, que se establece en verdadero?
novato
¿Dónde estás intentando acceder res.body(esto no es parte de mi ejemplo)? ¿Puede compartir algún código de muestra en su pregunta original para aclarar dónde podría estar su problema?
Ashley 'CptLemming' Wilson
1
Intenté acceder a res.body desde la respuesta json que se devolvió en la primera función .then (). He agregado una muestra a mi pregunta original para mayor claridad. ¡Gracias!
noob
1
Impresionante, usando react y request native, y preguntándose qué demonios hacer con un ReadableStream, y esto hizo el truco. ++
edencorbin
Solo un aviso, parece obvio, ¡pero asegúrate de que el backend que estás golpeando realmente proporcione JSON válido! Definitivamente no hablando por experiencia.
abelito
44

Algunas personas pueden encontrar un asyncejemplo útil:

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

json()convierte el cuerpo de la respuesta de ReadableStreama en un objeto json.

Las awaitdeclaraciones deben estar envueltas en una asyncfunción, sin embargo, puede ejecutarlas awaitdirectamente en la consola de Chrome (a partir de la versión 62).

Navidad
fuente
1
A veces, la verdadera respuesta para usted es realmente # 2 jaja, tiene sentido por qué harían .json () asíncrono, pero no fue inmediatamente obvio
Sanchit Batra
29

res.json()devuelve una promesa Tratar ...

res.json().then(body => console.log(body));
pinoyyid
fuente
3
Intenté esto, e imprimió la Promesa en lugar del cuerpo.
reectrix
Intente encadenar las .thenllamadas:fetch(...).then(res => res.json()).then(data => console.log(data))
Óscar Gómez Alcañiz
12

Un poco tarde para la fiesta, pero tuve algunos problemas para obtener algo útil de un ReadableStreamLlegó un solicitud producida a partir de un lote de Odata $ usando el Marco de Sharepoint.

Tuve problemas similares a los de OP, pero la solución en mi caso fue usar un método de conversión diferente que .json(). En mi caso .text()funcionó a las mil maravillas. Sin embargo, fue necesario jugar un poco para obtener algunos JSON útiles del archivo de texto.

Dan Mehlqvist
fuente
2
¡Gracias! Esto funcionó para mí. Estoy enviando una respuesta http Illuminate desde mi servidor Laravel con un simple return $data;. Finalmente pude leer esta respuesta en el navegador confetch(...).then(response => response.text()).then(data => console.log(data));
Cameron Hudson el
10

Si solo desea la respuesta como texto y no desea convertirla en JSON, use https://developer.mozilla.org/en-US/docs/Web/API/Body/text y luego thenpara obtener la respuesta real resultado de la promesa:

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

o

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

No me gustan los encadenamientos. El segundo entonces no tiene acceso al estado. Como se indicó antes, 'response.json ()' devuelve una promesa. Devolver el resultado de 'response.json ()' en un acto similar a un segundo entonces. Tiene la ventaja adicional de estar dentro del alcance de la respuesta.

return fetch(url, params).then(response => {
    return response.json().then(body => {
        if (response.status === 200) {
            return body
        } else {
            throw body
        }
    })
})
Mardok
fuente
El encadenamiento le thenayuda a recuperar el valor final resuelto (el body). Anidarlos evita que pueda obtener el bodyvalor sin una devolución de llamada o algún mecanismo de este tipo. Imagínese esto: let body = await fetch(...).then(res => res.json()).then(data => data). Esto no funcionaría de la manera anidada. Para verificarlo response.status, siempre puede hacer throwuna excepción dentro de la primera theny agregar una catcha toda la cadena de promesa.
Óscar Gómez Alcañiz
0

Tenga en cuenta que solo puede leer una secuencia una vez, por lo que en algunos casos, es posible que deba clonar la respuesta para leerla 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
fuente