React PWA中Workbox Background Sync请求体为空问题求助
Workbox Background Sync 重放请求时请求体为空问题
问题背景
我们内部的React PWA日均服务700名用户,采用Workbox Background Sync处理文件上传。多数场景功能正常:用户离线时发起的上传请求会存入indexedDB,恢复网络后自动重放。但部分请求出现异常:请求已正确存入indexedDB,但重放调用API时请求体为空(见截图)。原请求无问题,应用已上线近一年且经过充分测试,文件采用Base64格式上传,未使用formData。
路由注册代码
const routesToRegister = [ { pattern: /.*\/file/, method: ['POST', 'DELETE'], }, { pattern: /.*\/post_it/, method: ['POST', 'DELETE'], }, { pattern: /.*\/report/, method: ['POST'], }, { pattern: /.*\/arrival/, method: ['PATCH'], }, { pattern: /.*\/product/, method: ['PATCH'], }, ]; routesToRegister.forEach((route) => { route.method.forEach((method) => { registerRoute( route.pattern, new NetworkOnly({ plugins: [bgSyncPlugin], }), method, ); }); });
问题原因
Workbox默认的请求克隆逻辑在处理**可读流(ReadableStream)**类型的请求体时,会因为流被一次性消费导致重放时无法读取内容。Base64格式的请求体如果以流的形式发送,第一次存入indexedDB时流已被读取,重放时就会出现空请求体的情况。
解决方案
通过自定义requestWillReplay回调,手动克隆请求并重新构建可重复读取的请求体:
const bgSyncPlugin = new BackgroundSyncPlugin('myQueue', { requestWillReplay: async ({ request }) => { // 针对POST/PATCH这类带请求体的方法处理 if (['POST', 'PATCH'].includes(request.method)) { // 读取请求体内容并转为字符串 const bodyContent = await request.text(); // 重新创建Request对象,确保请求体可重复使用 return new Request(request.url, { method: request.method, headers: new Headers(request.headers), body: bodyContent, mode: request.mode, credentials: request.credentials, cache: request.cache, redirect: request.redirect, referrer: request.referrer, }); } return request; }, }); // 原路由注册代码保持不变 const routesToRegister = [ // ... 原有路由配置 ]; routesToRegister.forEach((route) => { route.method.forEach((method) => { registerRoute( route.pattern, new NetworkOnly({ plugins: [bgSyncPlugin], }), method, ); }); });
额外验证步骤
- 检查indexedDB存储:在浏览器DevTools的「Application > IndexedDB > workbox-background-sync > requests」中查看请求的
body字段,确认存储的内容完整。 - 确认请求头:确保
Content-Type与后端预期一致(比如Base64上传用text/plain或application/json),避免解析失败。 - 跨域配置检查:如果API是跨域的,确保请求的
mode和credentials设置正确,重放时不会因跨域策略丢失请求体。
内容的提问来源于stack exchange,提问作者Floran
相关产品推荐
相关产品推荐

