Recuperare dati da un oggetto ReadableStream?


135

Come posso ottenere informazioni da un ReadableStreamoggetto?

Sto usando l'API Fetch e non vedo questo per essere chiaro dalla documentazione.

Il corpo viene restituito come ReadableStreame vorrei semplicemente accedere a una proprietà all'interno di questo flusso. In Risposta negli strumenti di sviluppo del browser, sembra che queste informazioni siano organizzate in proprietà, sotto forma di un oggetto 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();
    })


2
@FrancescoPezzella Grazie per la risposta. Ho provato response.Body.json(), ma sto ottenendo corsivo TypeError: Impossibile leggere la proprietà 'json' di corsivo indefinito . Questo perché anche la proprietà bodyUsed è impostata su false? Tuttavia, posso visualizzare questo corpo nella scheda risposta negli strumenti per sviluppatori del browser. C'è un messaggio di errore che vorrei recuperare.
noob,

Quindi il tuo problema è puramente correlato alla condizione di errore 400? Cosa succede se si cambia il gestore in console.log(res.json());? Vedi i dati che ti aspetti?
Ashley 'CptLemming' Wilson

@noob Stai provando a leggere la risposta come stream se res.status == 200?
ospite271314

Sono solo io o quella documentazione è chiaramente sbagliata? L'ho risolto con le soluzioni su queste risposte però.
Lucio,

Risposte:


177

Per accedere ai dati da un ReadableStreamdevi chiamare uno dei metodi di conversione (documenti disponibili qui ).

Come esempio:

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

MODIFICA: Se il tipo di restituzione dei dati non è JSON o non si desidera JSON, utilizzaretext()

Come esempio:

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

Spero che questo aiuti a chiarire le cose.


1
Grazie per la risposta. Ho provato questo e sto ancora ottenendo lo stesso errore in cui res.body non è definito. Sono in grado di recuperare lo stato comunque nella prima funzione then () con res.status. Sembra che solo il corpo sia un oggetto ReadableStream. Sembra avere una proprietà bloccata, che è impostata su true?
Noob,

Dove stai cercando di accedere res.body(questo non fa parte del mio esempio)? Riesci a condividere un po 'di codice di esempio nella tua domanda originale per chiarire dove potrebbe essere il tuo problema.
Ashley 'CptLemming' Wilson

1
Ho provato ad accedere a res.body dalla risposta json che è stata restituita nella prima funzione .then (). Ho aggiunto un campione alla mia domanda originale per maggiore chiarezza. Grazie!
Noob,

1
Fantastico, usare reagire e richiedere nativi e chiedersi cosa c'entra il mondo con un ReadableStream, e questo ha funzionato. ++
edencorbin,

Solo un headsup, sembra un gioco da ragazzi, ma assicurati che il backend che stai colpendo fornisca effettivamente JSON valido! Sicuramente non parliamo per esperienza.
abelito,

44

Alcune persone potrebbero trovare asyncutile un esempio:

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

json()converte il corpo della risposta da a ReadableStreama un oggetto json.

Le awaitistruzioni devono essere racchiuse in una asyncfunzione, tuttavia è possibile eseguire le awaitistruzioni direttamente nella console di Chrome (dalla versione 62).


1
A volte la vera risposta per te è davvero # 2 haha, ha senso il motivo per cui renderebbero .json () asincrono ma non era immediatamente ovvio
Sanchit Batra

29

res.json()restituisce una promessa. Provare ...

res.json().then(body => console.log(body));

3
Ho provato questo, e ha stampato la Promessa invece del corpo.
reectrix,

Prova a concatenare le .thenchiamate:fetch(...).then(res => res.json()).then(data => console.log(data))
Óscar Gómez Alcañiz,

12

Un po 'in ritardo alla festa, ma ho avuto dei problemi con ottenere qualcosa di utile da un ReadableStream prodotto generato da una richiesta batch di Odata $ utilizzando Sharepoint Framework.

Aveva problemi simili a quelli di OP, ma la soluzione nel mio caso era quella di utilizzare un metodo di conversione diverso rispetto a .json(). Nel mio caso ha .text()funzionato come un fascino. Era tuttavia necessario un po 'di armeggiamento per ottenere qualche utile JSON dal file di testo.


2
Grazie! Questo ha funzionato per me. Sto inviando una risposta http Illuminate dal mio server Laravel con un semplice return $data;. Sono stato finalmente in grado di leggere questa risposta nel browser confetch(...).then(response => response.text()).then(data => console.log(data));
Cameron Hudson il

10

Se vuoi solo la risposta come testo e non vuoi convertirla in JSON, usa https://developer.mozilla.org/en-US/docs/Web/API/Body/text e poi thenper ottenere l'effettivo risultato della promessa:

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

2

Non mi piacciono i concatenati. Il secondo quindi non ha accesso allo stato. Come affermato in precedenza, "response.json ()" restituisce una promessa. Restituisce quindi il risultato di "response.json ()" in un atto simile a un secondo. Ha l'ulteriore vantaggio di essere nell'ambito della risposta.

return fetch(url, params).then(response => {
    return response.json().then(body => {
        if (response.status === 200) {
            return body
        } else {
            throw body
        }
    })
})

Il concatenamento thenti aiuta a recuperare il valore risolto finale (il body). La loro nidificazione ti impedisce di essere in grado di ottenere il bodyvalore senza un callback o qualche meccanismo del genere. Immaginate questo: let body = await fetch(...).then(res => res.json()).then(data => data). Questo non funzionerebbe nel modo annidato. Per verificare che response.statustu possa sempre fare throwun'eccezione all'interno del primo thene aggiungere un catcha tutta la catena di promesse.
Óscar Gómez Alcañiz,

0

Tieni presente che puoi leggere uno stream solo una volta, quindi in alcuni casi potrebbe essere necessario clonare la risposta per leggerlo ripetutamente:

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))
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.