You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用response.json()后response.body被锁定的原因及解锁方法(以便调用cancel())

调用response.json()后response.body被锁定的原因及解锁方法(以便调用cancel())

嘿,我来给你把这个问题讲明白哈!

首先说为啥response.body会显示locked: true——这是Fetch API的设计规则:响应体(也就是body对应的可读流)只能被「消费」一次。当你调用response.json()的时候,这个方法会把整个响应体的内容全部读取出来,然后自动关闭这个流,所以之后这个body就被锁定了,没法再对它进行任何读取或操作了。

接下来你关心的怎么「解锁」或者说怎么调用cancel(),得分两种情况来看:

1. 如果你想取消整个请求(而不是操作已读取的响应体)

如果你的需求是在请求还没完成的时候中断它,那不能等拿到response之后再处理,得提前用AbortController来做:

你需要先创建一个AbortController实例,把它的signal参数传给fetch方法,之后只要调用controller.abort()就能随时取消请求。举个例子:

async function getData() {
  const url = "http://jsonplaceholder.typicode.com/users";
  // 创建AbortController实例
  const controller = new AbortController();
  const { signal } = controller;

  // 比如模拟3秒后自动取消请求(你也可以在按钮点击等事件里调用controller.abort())
  setTimeout(() => controller.abort(), 3000);

  try {
    // 把signal传入fetch,绑定请求和控制器
    const response = await fetch(url, { signal });
    if (!response.ok) throw new Error(`Response status: ${response.status}`);

    // 只有请求没被取消,才会走到这里读取响应
    const json = await response.json();
    console.log("获取到的数据:", json);
    console.log("body是否锁定:", response.body.locked); // 这里会是true,因为json()已经消费了响应体
  } catch (error) {
    // 区分取消请求的错误和其他错误
    if (error.name === "AbortError") {
      console.log("请求已经被取消啦");
    } else {
      console.error("请求出错:", error.message);
    }
  }
}

getData();

这种方式是真正意义上的「取消请求」,而且必须在响应体被消费(比如调用json())之前执行才有效——如果已经拿到了response,说明请求已经完成了,这时候再取消也没用了。

2. 如果你只是想保留原response的body不被锁定

要是你的需求不是取消请求,只是不想让原response的body被锁定,那可以先克隆一份响应,然后消费克隆出来的响应体,原响应的body就不会被锁定了:

async function getData() {
  const url = "http://jsonplaceholder.typicode.com/users";
  try {
    const response = await fetch(url);
    if (!response.ok) throw new Error(`Response status: ${response.status}`);

    // 克隆一份响应
    const clonedResponse = response.clone();
    // 消费克隆出来的响应体
    const json = await clonedResponse.json();
    console.log("克隆响应的数据:", json);
    // 原response的body还没被消费,所以没锁定
    console.log("原response.body是否锁定:", response.body.locked); // false
  } catch (error) {
    console.error(error.message);
  }
}

不过要注意,这种方法只是保留了原响应体的可操作性,并不能帮你取消已经完成的请求哦。

总结一下

  • 锁定原因:response.json()会一次性读取并关闭响应体流,响应体只能被消费一次,所以之后就锁定了。
  • 解决思路:
    • 要取消请求:提前用AbortController绑定fetch,通过controller.abort()中断请求(必须在响应体被消费前执行)。
    • 要保留原body不锁定:克隆响应后消费克隆体,原响应的body不会被锁定。

备注:内容来源于stack exchange,提问作者kofifus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 08:34:31