javascript fetch-无法在“响应”上执行“ json”:主体流已锁定


107

当请求状态大于400(我尝试过400、423、429个状态)时,提取无法读取返回的json内容。浏览器控制台中显示以下错误

未捕获(承诺)TypeError:无法在“ Response”上执行“ json”:主体流已锁定

我显示了返回的响应对象的内容,如下所示:

在此处输入图片说明

但是几个月前我仍然可以使用它。

我的问题如下:

  • 这仅仅是Chrome浏览器的行为还是提取标准的更改?
  • 有什么方法可以获取这些状态的身体含量吗?

PS:我的浏览器版本是Google Chrome 70.0.3538.102(正式版本)(64位)


这意味着您正在从api获得响应,但响应不是有效的json,您是否在请求中发送了所有必需的参数?
kiranvj

@kiranvj我验证了我的数据,内容相同,只是将状态码更改为200以正确获取它。
露娜

1
我有同样的问题,但是我的状态是200,您最终是如何解决的?
DavSev '18年

@DavSev对于特定的状态码,我通过axios获取了返回数据
Luna

1
它也发生在200。
schlingel

Answers:


175

我也遇到了这个错误,但发现它与Response的状态无关,真正的问题是您只能消费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块中消耗多个。


5
您可以response.clone()在食用它之前。
balduran

真好 我有一个console.log(r.json()); return r.json();打破它。
mewc

2
谢谢它为我工作.....谁能解释这个奇怪的行为?
萨钦

74

Response.clone()到克隆Response

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

19
这对我来说非常有效,但是任何人都明白为什么这样做是必要的吗?我查了一下,发现有时候读者一旦开始阅读Response.body,它就会锁定在该读者身上。但是从我所看到的(至少在我的代码中),什么都还没开始读……是否有关于可读流如何自动锁定的解释?
詹明

5
我遇到了同样的问题,但发现我的Chrome开发工具的监视面板中有“ res.json()”,该问题在代码本身之前已得到解决!
FelipeDrumond

1
等等,什么?@FelipeDrumond多数民众赞成在一个疯狂的(非)错误!
乔治·莫尔

@GeorgeMauer好吧,如果我们只能运行一次response.json(),并且您的chrome dev工具监视面板在代码之前运行该代码,那么您将有一个例外,因为您运行了两次response.json()!
FelipeDrumond19年

参考MDN
foxiris

7

像“ json”,“ text”这样的响应方法可以被调用一次,然后锁定。张贴的响应图像显示主体已锁定。这意味着您已经称呼“ then”,“ catch”。要对此重做,您可以尝试以下操作。

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

要么

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

3

我知道为时已晚,但可以为某人提供帮助:

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


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而不是用完的response1):

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 { ---- })
        }
    } 
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.