Daten von einem ReadableStream-Objekt abrufen?

135

Wie kann ich Informationen von einem ReadableStreamObjekt erhalten?

Ich verwende die Fetch-API und sehe dies nicht in der Dokumentation.

Der Körper wird als zurückgegeben ReadableStreamund ich möchte einfach auf eine Eigenschaft innerhalb dieses Streams zugreifen. Unter Antwort in den Browser-Entwicklungstools scheinen diese Informationen in Form eines JavaScript-Objekts in Eigenschaften organisiert zu sein.

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();
    })
Anfänger
quelle
5
Body API Referenz
Francesco Pezzella
2
@FrancescoPezzella Danke für die Antwort. Ich habe es versucht response.Body.json(), aber es wird kursiv angezeigt. TypeError: Die Eigenschaft 'json' von undefiniertem kursiv kann nicht gelesen werden . Liegt das daran, dass die Eigenschaft bodyUsed ebenfalls auf false gesetzt ist? Ich kann diesen Text jedoch unter der Registerkarte "Antwort" in den Browser-Entwicklertools anzeigen. Es gibt eine Fehlermeldung, die ich abrufen möchte.
Noob
Ihr Problem hängt also ausschließlich mit der Fehlerbedingung 400 zusammen? Was passiert, wenn Sie den Handler auf ändern console.log(res.json());? Sehen Sie die Daten, die Sie erwarten?
Ashley 'CptLemming' Wilson
@noob Versuchen Sie, die Antwort als Stream zu lesen, wenn res.status == 200?
guest271314
Ist es nur ich oder ist die Dokumentation einfach falsch? Ich habe es jedoch mit den Lösungen für diese Antworten behoben.
Lucio

Antworten:

176

Um von einem auf die Daten zugreifen zu können ReadableStream, müssen Sie eine der Konvertierungsmethoden aufrufen (Dokumente hier verfügbar ).

Als Beispiel:

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

BEARBEITEN: Wenn Ihr Datenrückgabetyp nicht JSON ist oder Sie JSON nicht möchten, verwenden Sietext()

Als Beispiel:

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

Hoffe, das hilft, die Dinge zu klären.

Ashley 'CptLemming' Wilson
quelle
1
Danke für die Antwort. Ich habe dies versucht und erhalte immer noch den gleichen Fehler, bei dem res.body undefiniert ist. Ich kann den Status jedoch zuerst in der Funktion then () mit res.status abrufen. Es scheint, dass nur der Körper ein ReadableStream-Objekt ist. Es scheint eine Eigenschaft gesperrt zu haben, die auf true gesetzt ist?
Noob
Wo möchten Sie zugreifen res.body(dies ist nicht Teil meines Beispiels)? Können Sie einen Beispielcode in Ihrer ursprünglichen Frage freigeben, um klarer zu machen, wo Ihr Problem liegen könnte?
Ashley 'CptLemming' Wilson
1
Ich habe versucht, über die json-Antwort, die in der ersten .then () -Funktion zurückgegeben wurde, auf res.body zuzugreifen. Ich habe meiner ursprünglichen Frage zur besseren Übersicht ein Beispiel hinzugefügt. Vielen Dank!
Noob
1
Genial, mit React und Request Native und mit der Frage, was in aller Welt mit einem ReadableStream zu tun ist, und das hat den Trick getan. ++
Edencorbin
Nur ein Headsup, scheint ein Kinderspiel zu sein, aber stellen Sie sicher, dass das Backend, das Sie treffen, tatsächlich gültigen JSON bereitstellt! Ich spreche definitiv nicht aus Erfahrung.
Abelito
43

Einige Leute mögen ein asyncBeispiel nützlich finden:

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

json()konvertiert den Körper der Antwort von einem ReadableStreamin ein JSON-Objekt.

Die awaitAnweisungen müssen in eine asyncFunktion eingeschlossen sein. Sie können awaitAnweisungen jedoch direkt in der Konsole von Chrome ausführen (ab Version 62).

Noel
quelle
1
Manchmal ist die eigentliche Antwort für Sie wirklich # 2 haha, es macht Sinn, warum sie .json () asynchron machen würden, aber es war nicht sofort offensichtlich
Sanchit Batra
28

res.json()gibt ein Versprechen zurück. Versuchen ...

res.json().then(body => console.log(body));
Pinoyyid
quelle
3
Ich habe es versucht und es hat das Versprechen anstelle des Körpers ausgedruckt.
Reectrix
Versuchen Sie, die .thenAnrufe fetch(...).then(res => res.json()).then(data => console.log(data))
Óscar Gómez Alcañiz
12

Etwas spät zur Party, hatte aber einige Probleme damit, etwas Nützliches ReadableStreamaus einer Odata $ Batch-Anfrage herauszuholen , die das Sharepoint Framework verwendet.

Hatte ähnliche Probleme wie OP, aber die Lösung in meinem Fall bestand darin, eine andere Konvertierungsmethode als zu verwenden .json(). In meinem Fall .text()hat es wie ein Zauber funktioniert. Einige Fummelei war jedoch notwendig, um einige nützliche JSON aus der Textdatei zu erhalten.

Dan Mehlqvist
quelle
2
Danke dir! Das hat bei mir funktioniert. Ich sende eine Illuminate http-Antwort von meinem Laravel-Server mit einer einfachen return $data;. Ich konnte diese Antwort endlich im Browser mitfetch(...).then(response => response.text()).then(data => console.log(data));
Cameron Hudson
10

Wenn Sie die Antwort nur als Text wünschen und nicht in JSON konvertieren möchten, verwenden Sie https://developer.mozilla.org/en-US/docs/Web/API/Body/text und dann thenden tatsächlichen Ergebnis des Versprechens:

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

oder

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

Ich mag die Verkettung nicht. Der zweite hat dann keinen Zugriff auf den Status. Wie bereits erwähnt, gibt 'response.json ()' ein Versprechen zurück. Das Rückgabe des then-Ergebnisses von 'response.json ()' erfolgt in einer Aktion ähnlich einer Sekunde. Es hat den zusätzlichen Vorteil, im Umfang der Antwort zu sein.

return fetch(url, params).then(response => {
    return response.json().then(body => {
        if (response.status === 200) {
            return body
        } else {
            throw body
        }
    })
})
Mardok
quelle
Die Verkettung thenhilft Ihnen dabei, den endgültigen aufgelösten Wert (den body) abzurufen . Wenn Sie sie verschachteln, können Sie den bodyWert nicht ohne Rückruf oder einen solchen Mechanismus abrufen. Stellen Sie sich Folgendes vor : let body = await fetch(...).then(res => res.json()).then(data => data). Dies würde nicht auf verschachtelte Weise funktionieren. Um dies zu überprüfen response.status, können Sie immer throweine Ausnahme innerhalb der ersten machen thenund catchder gesamten Versprechenskette eine hinzufügen .
Óscar Gómez Alcañiz
0

Beachten Sie, dass Sie einen Stream nur einmal lesen können. In einigen Fällen müssen Sie die Antwort möglicherweise klonen, um sie wiederholt zu lesen:

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
quelle