为何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
相关产品推荐
相关产品推荐

