การดึงข้อมูลจาวาสคริปต์ - ไม่สามารถเรียกใช้งาน 'json' ใน 'การตอบกลับ': สตรีมเนื้อหาถูกล็อก


113

เมื่อสถานะคำขอมากกว่า 400 (ฉันลอง 400, 423, 429 สถานะ) การดึงข้อมูลไม่สามารถอ่านเนื้อหา json ที่ส่งคืนได้ ข้อผิดพลาดต่อไปนี้แสดงขึ้นในคอนโซลของเบราว์เซอร์

Uncaught (ตามสัญญา) TypeError: ล้มเหลวในการรัน 'json' ใน 'การตอบสนอง': สตรีมเนื้อหาถูกล็อค

ฉันแสดงเนื้อหาของวัตถุตอบกลับที่ส่งคืนดังนี้:

ใส่คำอธิบายภาพที่นี่

แต่ฉันยังสามารถใช้งานได้เมื่อหลายเดือนก่อน

คำถามของฉันมีดังนี้:

  • นี่เป็นเพียงพฤติกรรมของเบราว์เซอร์ Chrome หรือการเปลี่ยนแปลงมาตรฐานในการดึงข้อมูล?
  • มีวิธีใดบ้างในการรับเนื้อหาของรัฐเหล่านี้?

PS: เวอร์ชันเบราว์เซอร์ของฉันคือ Google Chrome 70.0.3538.102 (正式版本) (64 位)


ซึ่งหมายความว่าคุณได้รับการตอบกลับจาก api แต่ไม่ใช่ json ที่ถูกต้องคุณกำลังส่งพารามิเตอร์ที่จำเป็นทั้งหมดในคำขอหรือไม่
kiranvj

@kiranvj ฉันยืนยันข้อมูลของฉันเนื้อหาเดียวกันฉันเพิ่งเปลี่ยนรหัสสถานะเป็น 200 เพื่อให้ถูกต้อง
Luna

1
ฉันมีปัญหาเดียวกัน แต่สถานะของฉันคือ 200 คุณแก้ไขได้อย่างไรในที่สุด?
DavSev

@DavSev สำหรับรหัสสถานะเฉพาะฉันได้รับข้อมูลการส่งคืนผ่าน axios
Luna

1
มันเกิดขึ้นกับ 200 ด้วย
schlingel

คำตอบ:


187

ฉันพบข้อผิดพลาดนี้เช่นกัน แต่พบว่ามันไม่เกี่ยวข้องกับสถานะของการตอบสนองปัญหาที่แท้จริงคือคุณสามารถบริโภคได้Response.json()เพียงครั้งเดียวหากคุณบริโภคมากกว่าหนึ่งครั้งข้อผิดพลาดจะเกิดขึ้น

เช่นด้านล่าง:

    fetch('http://localhost:3000/movies').then(response =>{
    console.log(response);
    if(response.ok){
         console.log(response.json()); //first consume it in console.log
        return response.json(); //then consume it again, the error happens

    }

ดังนั้นวิธีแก้ไขคือหลีกเลี่ยงการบริโภคResponse.json()มากกว่าหนึ่งครั้งในการthenบล็อก


6
คุณสามารถresponse.clone()ก่อนที่จะบริโภคมัน
balduran

1
ดี. ฉันมีสิ่งconsole.log(r.json()); return r.json();ที่ทำลายมัน
mewc

2
ขอบคุณที่ทำงานให้ฉัน ..... ใครช่วยอธิบายพฤติกรรมแปลก ๆ นี้ได้ไหม
Sachin

83

ใช้Response.clone()ในการโคลนResponse

ตัวอย่าง

fetch('yourfile.json').then(res=>res.clone().json())

21
สิ่งนี้ได้ผลดีสำหรับฉัน แต่มีใครเข้าใจว่าทำไมจึงจำเป็น? ฉันมองขึ้นไปและฉันเห็นว่าบางครั้งเมื่อผู้อ่านเริ่มอ่านResponse.bodyมันจะถูกล็อกไม่ให้ผู้อ่านคนนั้นเข้ามาอ่าน แต่จากสิ่งที่ฉันเห็น (อย่างน้อยก็ในรหัสของฉัน) ไม่มีอะไรเริ่มอ่าน ... มีคำอธิบายว่าสตรีมที่อ่านได้จะถูกล็อคโดยอัตโนมัติได้อย่างไร
jenming

6
ฉันมีปัญหาเดียวกัน แต่พบว่าฉันมี "res.json ()" ในแผงนาฬิกาของฉันในเครื่องมือ Chrome dev ซึ่งกำลังได้รับการแก้ไขก่อนโค้ด
FelipeDrumond

1
รออะไร? @FelipeDrumond นั่นเป็นบั๊ก (ไม่ใช่) บ้า!
George Mauer

@GeorgeMauer ถ้าเราสามารถเรียกใช้ response.json () ได้เพียงครั้งเดียวและแผงหน้าปัดเครื่องมือ Chrome dev ของคุณทำงานก่อนโค้ดของคุณคุณจะมีข้อยกเว้นเพราะคุณรัน response.json () สองครั้ง!
FelipeDrumond

อ้างอิงMDN
foxiris

9

วิธีการตอบสนองเช่น 'json', 'text' สามารถเรียกได้ครั้งเดียวจากนั้นจะล็อก ภาพการตอบกลับที่โพสต์แสดงว่าเนื้อหาถูกล็อก ซึ่งหมายความว่าคุณได้เรียกปุ่ม "แล้ว" "จับ" แล้ว คุณสามารถลองทำสิ่งต่อไปนี้ได้

fetch(url)
    .then(response=> response.body.json())
    .then(myJson=> console.log(myJson))

หรือ

fetch(url)
    .catch(response=> response.body.json())
    .catch(myJson=> console.log(myJson))

5

ฉันรู้ว่ามันสายเกินไป แต่มันช่วยใครบางคนได้:

let response = await fetch(targetUrl);
let data = await response.json();

สิ่งที่ฉันต้องการในการแก้ไขปัญหานี้โดยใช้ไวยากรณ์ async / await ขอบคุณ!
ttemple

2

ฉันยังติดอยู่ในนี้ แต่สิ่งนี้ได้ผลสำหรับฉัน

fetch(YOUR_URL)
.then(res => {
  try {
    if (res.ok) {
      return res.json()
    } else {
      throw new Error(res)
    }
  }
  catch (err) {
    console.log(err.message)
    return WHATEVER_YOU_WANT_TO_RETURN
  }
})
.then (resJson => {
  return resJson.data
})
.catch(err => console.log(err))

โชคดี


ตัวอย่างเกี่ยวกับการดึงข้อมูลใน MDN github.com/mdn/fetch-examples/blob/master/fetch-json/…
Magaesh

1

ฉันใช้วัตถุตอบกลับซ้ำโดยไม่ได้ตั้งใจซึ่งคล้ายกับสิ่งนี้:

const response = await new ReleasePresetStore().findAll();
const json = await response.json();
this.setState({ releasePresets: json });

const response2 = await new ReleasePresetStore().findActive();
const json2 = await response.json();
this.setState({ active: json2 });
console.log(json2);

บรรทัดนี้:

const json2 = await response.json();

ควรเป็น (response2 แทนการตอบกลับที่ใช้แล้ว 1):

const json2 = await response2.json();

การใช้คำตอบก่อนหน้านี้ซ้ำไม่มีเหตุผลและเป็นการพิมพ์รหัสผิด ...



0

ดังที่กล่าวไว้ในคำถามเมื่อคุณพยายามใช้วัตถุตอบสนองเดียวกันร่างกายของคุณกำลังจะถูกล็อกเนื่องจากสถานะของวัตถุ สิ่งที่คุณทำได้คือจับค่าของอ็อบเจ็กต์การตอบกลับแล้วลองดำเนินการกับมัน (.then ()) โปรดปฏิบัติตามรหัสด้านล่าง

fetch('someurl').then(respose) => {
    let somedata = response.json(); // as you will capture the json response, body will not be locked anymore. 
    somedata.then(data) => {
        {
             error handling (if (data.err) { ---- })
        }
        {
             operations (else { ---- })
        }
    } 
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.