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

如何让Workbox SW保留请求失败的POST请求在队列中以便手动重发?

如何让Workbox Background Sync保留4xx状态的请求队列

默认情况下,Workbox的BackgroundSyncPlugin和Queue会在同步尝试完成后移除所有请求——不管服务器返回的是2xx还是4xx状态码,这就是你遇到的问题根源。要实现“仅移除成功请求,保留失败请求”的逻辑,必须自定义onSync回调,手动控制请求的移除时机。

解决方案:自定义onSync处理逻辑

核心思路是:在同步事件触发时,手动从队列中取出请求尝试发送,只有当响应状态码为2xx时,才将该请求从队列中移除;若返回4xx/5xx或网络失败,则保留请求在队列中,留待后续用户手动处理。

步骤1:创建自定义的BackgroundSync插件

import { BackgroundSyncPlugin, Queue } from 'workbox-background-sync';

// 创建队列实例
const postsQueue = new Queue('post-requests', {
  maxRetentionTime: 24 * 60, // 保留24小时
});

// 自定义onSync回调的插件
const customPostSyncPlugin = new BackgroundSyncPlugin('post-requests', {
  async onSync({ queue }) {
    let request;
    // 遍历队列中的所有请求
    while ((request = await queue.shiftRequest())) {
      try {
        // 克隆请求,因为Request对象只能被使用一次
        const clonedRequest = request.request.clone();
        const response = await fetch(clonedRequest);

        // 仅当响应成功(2xx)时,才确认请求已处理
        if (response.ok) {
          console.log('请求同步成功:', clonedRequest.url);
          // 这里不需要手动移除,因为shiftRequest已经取出,成功则不再放回
        } else {
          // 响应失败,将请求放回队列尾部
          console.log('请求同步失败(非2xx),保留队列:', clonedRequest.url);
          await queue.unshiftRequest(request);
          // 可以在这里记录错误信息,供前端展示给用户
        }
      } catch (error) {
        // 网络错误或其他异常,将请求放回队列尾部
        console.log('请求同步异常,保留队列:', request.request.url, error);
        await queue.unshiftRequest(request);
        // 跳出循环,避免一直重试失败的请求
        break;
      }
    }
  },
});

步骤2:注册路由时使用自定义插件

import { registerRoute, NetworkOnly } from 'workbox-routing';

registerRoute(
  ({ request }) => request.url.includes('example.com') && request.method === 'POST',
  new NetworkOnly({
    plugins: [customPostSyncPlugin],
  }),
);

为什么之前的尝试无效?

你之前在fetchDidSucceed中抛出错误的方式,无法改变默认onSync的行为——默认的Queue.replayRequests()方法会在每次请求完成后(无论成功或失败)自动移除请求,即使你抛出错误,它也只会捕获错误并停止后续请求,但已经处理过的请求还是会被移除。只有通过自定义onSync,才能完全控制请求的保留/移除逻辑。

手动触发同步的补充

如果需要让用户手动触发失败请求的同步,可以直接调用队列的replayRequests()方法,或者手动触发sync事件:

// 手动触发队列同步
await postsQueue.replayRequests();

// 或者通过Service Worker注册对象触发sync事件
if ('serviceWorker' in navigator) {
  const registration = await navigator.serviceWorker.ready;
  await registration.sync.register('post-requests');
}

内容的提问来源于stack exchange,提问作者stefanz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:40:55