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

为何JavaScript Fetch Response的body被判定为已使用?(PWA场景)

解决Service Worker中response.clone()报错:Response body is already used

问题根源

Response对象的body是一次性可读取资源,一旦通过以下方式消耗了body,就无法再次读取或克隆:

  • 调用response.text()/json()/blob()等方法读取内容
  • 将response返回给浏览器(浏览器会自动读取body用于渲染)
  • 调用cache.put()存入缓存(该方法会读取body生成缓存条目)

你的情况大概率是调用cache.put()时消耗了原始response的body,之后又尝试返回该response或对其进行克隆,导致报错。

解决方案:提前克隆Response

必须在任何消耗body的操作之前克隆Response,确保缓存和页面返回使用的是两个独立的Response实例。

正确的缓存优先策略代码示例

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
      .then(cachedResponse => {
        // 缓存优先:有缓存直接返回
        if (cachedResponse) {
          return cachedResponse;
        }

        // 无缓存则请求网络
        return fetch(event.request)
          .then(networkResponse => {
            // 关键步骤:先克隆Response
            const cachedCopy = networkResponse.clone();
            
            // 将克隆的副本存入缓存
            caches.open('your-cache-name-v1')
              .then(cache => {
                cache.put(event.request, cachedCopy);
              });

            // 返回原始Response给页面使用
            return networkResponse;
          });
      })
  );
});

额外注意事项

  • 克隆操作必须在任何读取body的动作之前执行,顺序不能颠倒
  • 如果需要同时读取response的内容(比如解析json)和存入缓存,也要先克隆:
    fetch(event.request).then(networkResponse => {
      const clone = networkResponse.clone();
      // 读取原始response的body
      networkResponse.json().then(data => { /* 处理数据 */ });
      // 用克隆的副本存缓存
      caches.open('cache').then(cache => cache.put(event.request, clone));
    });
    

内容的提问来源于stack exchange,提问作者Ykon O'Clast

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 18:33:22