ดึงข้อมูลจากอ็อบเจ็กต์ ReadableStream?


138

ฉันจะรับข้อมูลจากReadableStreamวัตถุได้อย่างไร?

ฉันใช้ Fetch API และไม่เห็นว่าสิ่งนี้ชัดเจนจากเอกสารประกอบ

กำลังส่งคืนร่างเป็นReadableStreamและฉันก็แค่ต้องการเข้าถึงคุณสมบัติภายในสตรีมนี้ ภายใต้การตอบสนองในเครื่องมือ dev ของเบราว์เซอร์ฉันดูเหมือนว่าจะมีข้อมูลนี้จัดเป็นคุณสมบัติในรูปแบบของวัตถุ 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 ขอบคุณสำหรับการตอบกลับ ฉันได้พยายามresponse.Body.json()แต่ฉันได้รับตัวเอียง TypeError: ไม่สามารถอ่านคุณสมบัติ 'JSON ของไม่ได้กำหนดตัวเอียง เป็นเพราะคุณสมบัติ bodyUsed ถูกตั้งค่าเป็นเท็จหรือไม่? อย่างไรก็ตามฉันสามารถดูเนื้อหานี้ได้ภายใต้แท็บการตอบกลับในเครื่องมือสำหรับนักพัฒนาเบราว์เซอร์ มีข้อความแสดงข้อผิดพลาดที่ฉันต้องการเรียกคืน
noob

ปัญหาของคุณเกี่ยวข้องกับเงื่อนไขข้อผิดพลาด 400 หรือไม่ จะเกิดอะไรขึ้นถ้าคุณเปลี่ยนตัวจัดการเป็นconsole.log(res.json());? คุณเห็นข้อมูลที่คุณคาดหวังหรือไม่?
Ashley 'CptLemming' Wilson

@noob คุณกำลังพยายามอ่านการตอบสนองเป็นสตรีมres.status == 200หรือไม่?
แขก 271314

เป็นเพียงฉันหรือเอกสารนั้นผิดธรรมดา ? ฉันแก้ไขด้วยวิธีแก้ปัญหาเกี่ยวกับคำตอบนี้แล้ว
Lucio

คำตอบ:


180

ในการเข้าถึงข้อมูลReadableStreamคุณต้องเรียกใช้วิธีการแปลงวิธีใดวิธีหนึ่ง (ดูเอกสารได้ที่นี่ )

ตัวอย่างเช่น:

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

แก้ไข:หากประเภทการส่งคืนข้อมูลของคุณไม่ใช่ JSON หรือคุณไม่ต้องการ JSON ให้ใช้text()

ตัวอย่างเช่น:

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

หวังว่านี่จะช่วยให้ทุกอย่างกระจ่างขึ้น


1
ขอบคุณสำหรับการตอบกลับ ฉันได้ลองสิ่งนี้แล้วและยังคงได้รับข้อผิดพลาดเดิมที่ res.body is undefined ฉันสามารถดึงสถานะอย่างไรก็ตามในฟังก์ชัน first then () ด้วย res.status ดูเหมือนว่ามีเพียงร่างกายเท่านั้นที่เป็นวัตถุ ReadableStream ดูเหมือนว่าจะมีคุณสมบัติถูกล็อคซึ่งตั้งค่าเป็น true?
noob

คุณกำลังพยายามเข้าถึงที่ไหนres.body(นี่ไม่ใช่ส่วนหนึ่งของตัวอย่างของฉัน) คุณสามารถแบ่งปันโค้ดตัวอย่างในคำถามเดิมของคุณเพื่อให้ชัดเจนขึ้นได้ไหมว่าปัญหาของคุณอยู่ที่ใด
Ashley 'CptLemming' Wilson

1
ฉันพยายามเข้าถึง res.body จากการตอบสนอง json ที่ส่งคืนในฟังก์ชัน. then () ก่อน ฉันได้เพิ่มตัวอย่างในคำถามเดิมของฉันเพื่อความชัดเจนยิ่งขึ้น ขอบคุณ!
noob

1
ยอดเยี่ยมมากโดยใช้การตอบสนองและการร้องขอแบบเนทีฟและสงสัยว่าจะทำอย่างไรกับ ReadableStream ในโลกนี้และนี่เป็นเคล็ดลับ ++
edencorbin

เพียงแค่การแจ้งเตือนดูเหมือนจะไม่ใช่เกมง่ายๆ แต่ตรวจสอบให้แน่ใจว่าแบ็กเอนด์ที่คุณกดปุ่มนั้นให้ JSON ที่ถูกต้องจริงๆ! ไม่ได้พูดจากประสบการณ์แน่นอน
abelito

46

บางคนอาจพบว่าasyncตัวอย่างมีประโยชน์:

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

json()แปลงร่างกายของการตอบสนองจาก a ReadableStreamเป็นวัตถุ json

awaitงบต้องถูกห่อในasyncฟังก์ชั่น แต่คุณสามารถเรียกใช้awaitงบโดยตรงในคอนโซลของ Chrome (เหมือนรุ่น 62)


1
บางครั้งคำตอบที่แท้จริงสำหรับคุณคือ # 2 ฮ่าฮ่ามันสมเหตุสมผลแล้วว่าทำไมพวกเขาถึงทำ. json () asynchronous แต่มันก็ไม่ชัดเจนในทันที
Sanchit Batra

29

res.json()คืนคำสัญญา ลอง ...

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

3
ฉันลองสิ่งนี้และพิมพ์คำสัญญาออกมาแทนร่างกาย
reectrix

ลองโซ่.thenโทร:fetch(...).then(res => res.json()).then(data => console.log(data))
ÓscarGómezAlcañiz

13

ไปงานปาร์ตี้ช้าไปหน่อย แต่มีปัญหาในการรับสิ่งที่เป็นประโยชน์จากReadableStreamคำขอแบทช์ $ Odata โดยใช้ Sharepoint Framework

มีปัญหาคล้ายกันกับ OP แต่วิธีแก้ปัญหาในกรณีของฉันคือใช้วิธีการแปลงที่แตกต่างจาก.json(). ในกรณีของฉัน.text()ทำงานเหมือนมีเสน่ห์ อย่างไรก็ตามการเล่นซอบางอย่างจำเป็นต้องได้รับ JSON ที่เป็นประโยชน์จากไฟล์ข้อความ


2
ขอบคุณ! สิ่งนี้ได้ผลสำหรับฉัน ฉันกำลังส่งการตอบกลับ Illuminate http จากเซิร์ฟเวอร์ Laravel ของฉันด้วยไฟล์return $data;. ในที่สุดฉันก็สามารถอ่านคำตอบนี้ในเบราว์เซอร์ด้วยfetch(...).then(response => response.text()).then(data => console.log(data));
Cameron Hudson

10

หากคุณต้องการเพียงแค่การตอบกลับเป็นข้อความและไม่ต้องการแปลงเป็น JSON ให้ใช้https://developer.mozilla.org/en-US/docs/Web/API/Body/textจากนั้นthenจึงจะได้รับจริง ผลลัพธ์ของคำสัญญา:

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

หรือ

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

2

ฉันไม่ชอบการล่ามโซ่ อย่างที่สองไม่มีสิทธิ์เข้าถึงสถานะ ตามที่ระบุไว้ก่อนที่ 'response.json ()' จะส่งคืนคำสัญญา ส่งคืนผลลัพธ์ของ 'response.json ()' ในการกระทำที่คล้ายกับวินาทีนั้น มีโบนัสเพิ่มเติมจากการอยู่ในขอบเขตของการตอบสนอง

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

การต่อโซ่thenช่วยให้คุณดึงค่าสุดท้ายที่แก้ไขได้ (the body) การซ้อนกันทำให้คุณไม่สามารถรับbodyค่าได้โดยไม่มีการเรียกกลับหรือกลไกบางอย่างของการจัดเรียง ลองนึกภาพสิ่งนี้: let body = await fetch(...).then(res => res.json()).then(data => data). สิ่งนี้จะไม่ทำงานในลักษณะที่ซ้อนกัน หากต้องการตรวจสอบresponse.statusคุณสามารถthrowมีข้อยกเว้นภายในข้อแรกได้thenเสมอและเพิ่ม a catchในห่วงโซ่สัญญาทั้งหมด
ÓscarGómezAlcañiz

0

โปรดทราบว่าคุณสามารถอ่านสตรีมได้เพียงครั้งเดียวดังนั้นในบางกรณีคุณอาจต้องโคลนคำตอบเพื่ออ่านซ้ำ:

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))
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.