Mengambil data dari objek ReadableStream?

135

Bagaimana saya bisa mendapatkan informasi dari suatu ReadableStreamobjek?

Saya menggunakan API Ambil dan saya tidak melihat ini jelas dari dokumentasi.

Tubuh sedang dikembalikan sebagai a ReadableStreamdan saya hanya ingin mengakses properti dalam aliran ini. Di bawah Respons di alat pengembang peramban, saya sepertinya mengatur informasi ini ke dalam properti, dalam bentuk objek 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();
    })
cupu
sumber
5
Referensi API tubuh
Francesco Pezzella
2
@FrancescoPezzella Terima kasih atas tanggapannya. Saya sudah mencoba response.Body.json(), tetapi saya mendapatkan italic TypeError: Tidak dapat membaca properti 'json' dari italic yang tidak terdefinisi . Apakah ini karena properti bodyUsed juga disetel ke false? Namun saya dapat melihat badan ini di bawah tab respons di alat pengembang browser. Ada pesan kesalahan yang ingin saya ambil.
noob
Jadi masalah Anda murni terkait dengan kondisi kesalahan 400? Apa yang terjadi jika Anda mengganti pawang console.log(res.json());? Apakah Anda melihat data yang Anda harapkan?
Ashley 'CptLemming' Wilson
@noob Apakah Anda mencoba membaca respons sebagai streaming jika res.status == 200?
guest271314
Apakah hanya saya atau bahwa dokumentasi polos yang salah? Saya memperbaikinya dengan solusi pada jawaban ini.
Lucio

Jawaban:

177

Untuk mengakses data dari ReadableStreamAnda harus memanggil salah satu metode konversi (dokumen tersedia di sini ).

Sebagai contoh:

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: Jika tipe pengembalian data Anda bukan JSON atau Anda tidak ingin JSON, gunakantext()

Sebagai contoh:

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

Semoga ini bisa membantu membereskan semuanya.

Ashley 'CptLemming' Wilson
sumber
1
Terima kasih atas tanggapannya. Saya telah mencoba ini dan saya masih mendapatkan kesalahan yang sama di mana res.body tidak terdefinisi. Saya dapat mengambil status namun dalam fungsi first () dengan res.status. Tampaknya hanya tubuh yang merupakan objek ReadableStream. Tampaknya memiliki properti terkunci, yang disetel ke true?
noob
Di mana Anda mencoba mengakses res.body(ini bukan bagian dari contoh saya)? Bisakah Anda membagikan beberapa kode sampel dalam pertanyaan awal Anda untuk membuatnya lebih jelas di mana masalah Anda mungkin.
Ashley 'CptLemming' Wilson
1
Saya mencoba mengakses res.body dari respons json yang dikembalikan pada fungsi .then () yang pertama. Saya telah menambahkan sampel ke pertanyaan awal saya untuk kejelasan lebih lanjut. Terima kasih!
noob
1
Luar biasa, menggunakan reaksi dan meminta yang asli, dan bertanya-tanya apa yang harus dilakukan dengan ReadableStream, dan ini berhasil. ++
edencorbin
Hanya sebuah headup, tampaknya seperti no-brainer, tetapi pastikan backend yang Anda pukul benar-benar memberikan JSON yang valid! Jelas tidak berbicara dari pengalaman.
abelito
44

Beberapa orang mungkin menemukan asynccontoh yang bermanfaat:

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

json()mengubah tubuh respons dari objek ReadableStreamke objek json.

The awaitpernyataan harus dibungkus dalam sebuah asyncfungsi, namun Anda dapat menjalankan awaitpernyataan langsung di konsol Chrome (sebagai versi 62).

Noel
sumber
1
Terkadang jawaban sebenarnya untuk Anda benar-benar adalah # 2 haha, masuk akal mengapa mereka membuat .json () asinkron tetapi tidak segera jelas
Sanchit Batra
29

res.json()mengembalikan janji. Coba ...

res.json().then(body => console.log(body));
pinoyyid
sumber
3
Saya mencoba ini, dan itu mencetak Janji bukan tubuh.
reectrix
Cobalah untuk membuat .thenpanggilan:fetch(...).then(res => res.json()).then(data => console.log(data))
Óscar Gómez Alcañiz
12

Sedikit terlambat ke pesta tetapi memiliki beberapa masalah dengan mengeluarkan sesuatu yang bermanfaat dari a ReadableStream dihasilkan dari permintaan $ batch Odata menggunakan Sharepoint Framework.

Punya masalah serupa dengan OP, tetapi solusi dalam kasus saya adalah menggunakan metode konversi yang berbeda dari .json(). Dalam kasus saya .text()bekerja seperti pesona. Namun beberapa biola diperlukan untuk mendapatkan JSON yang berguna dari filefile.

Dan Mehlqvist
sumber
2
Terima kasih! Ini berhasil untuk saya. Saya mengirimkan respons http Illuminate dari server Laravel saya dengan sederhana return $data;. Saya akhirnya bisa membaca respons ini di browser denganfetch(...).then(response => response.text()).then(data => console.log(data));
Cameron Hudson
10

Jika Anda hanya ingin respons sebagai teks dan tidak ingin mengubahnya menjadi JSON, gunakan https://developer.mozilla.org/en-US/docs/Web/API/Body/text dan kemudian thenuntuk mendapatkan yang sebenarnya hasil dari janji:

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

atau

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

Saya tidak suka chaining thens. Yang kedua kemudian tidak memiliki akses ke status. Seperti yang dinyatakan sebelumnya 'response.json ()' mengembalikan janji. Mengembalikan hasil kemudian dari 'response.json ()' dalam tindakan yang mirip dengan yang kedua itu. Ini memiliki bonus tambahan berada dalam ruang lingkup respons.

return fetch(url, params).then(response => {
    return response.json().then(body => {
        if (response.status === 200) {
            return body
        } else {
            throw body
        }
    })
})
Mardok
sumber
Rantai thenmembantu Anda mengambil nilai akhir yang diselesaikan (the body). Bersarang mereka mencegah Anda mendapatkan bodynilai tanpa panggilan balik atau mekanisme semacam itu. Bayangkan ini: let body = await fetch(...).then(res => res.json()).then(data => data). Ini tidak akan bekerja dengan cara bersarang. Untuk memeriksa response.statusAnda selalu bisa throwpengecualian di dalam yang pertama then, dan menambahkan catchrantai keseluruhan janji.
Óscar Gómez Alcañiz
0

Perhatikan bahwa Anda hanya dapat membaca streaming sekali, jadi dalam beberapa kasus, Anda mungkin perlu mengkloning respons agar dapat membacanya berulang kali:

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
sumber