在重新连接到网络后重试请求

当您向网络服务器发出请求时,可能会失败。这可能是因为用户连接中断,或者远程服务器已宕机。

虽然本文档主要侧重于处理 Service Worker 中的 GET 请求,但 POSTPUTDELETE 等其他方法可能也会发挥作用。这些方法通常用于与后端 API 通信,以便为 Web 应用提供数据。如果这些请求在缺少 Service Worker 的情况下失败,则用户必须在恢复在线状态后手动重试,而这不是用户可能会一直记住的操作。

如果您的应用属于这种情况,并且其中也包含 Service Worker,那么您最好在用户恢复在线状态后重新尝试发送失败的请求。BackgroundSync API 解决了这个问题。如果 Service Worker 检测到失败的网络请求,它可以注册为在浏览器检测到连接已返回时接收 sync 事件。即使用户已经离开注册该事件的页面,系统也可能会传递 sync 事件,这比其他重试失败请求的方法更有效。

Workbox 通过 workbox-background-sync 模块抽象化此 API,使 BackgroundSync API 更易于与其他 Workbox 模块结合使用。它还针对尚不支持 BackgroundSync 的浏览器实现了后备策略。

基本用法

BackgroundSyncPluginworkbox-background-sync 模块导出,可用于将失败的请求加入队列,并在将来触发 sync 事件时重试这些请求:

import {BackgroundSyncPlugin} from 'workbox-background-sync';
import {registerRoute} from 'workbox-routing';
import {NetworkOnly} from 'workbox-strategies';

const bgSyncPlugin = new BackgroundSyncPlugin('myQueueName', {
  maxRetentionTime: 24 * 60 // Retry for max of 24 Hours (specified in minutes)
});

registerRoute(
  /\/api\/.*\/*.json/,
  new NetworkOnly({
    plugins: [bgSyncPlugin]
  }),
  // An optional third parameter specifies the request method
  'POST'
);

此处,BackgroundSyncPlugin 应用于与检索 JSON 数据的 API 路由的 POST 请求路由匹配。如果用户处于离线状态,BackgroundSyncPlugin 会在用户恢复在线状态后重试请求,但最长不会超过一天。

高级用法

workbox-background-sync 还提供了 Queue 类,您可以将失败的请求实例化并将其添加到该类。与 BackgroundSyncPlugin 一样,失败的请求会存储在 IndexedDB 中,并在浏览器认为连接恢复时尝试。

创建队列

如需创建队列,请使用表示队列名称的字符串实例化 Queue 对象:

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

const queue = new Queue('myQueueName');

队列名称会用作标记名称的一部分,标记名称由全局 SyncManager 提供的 register() 方法创建。它也是 IndexedDB 数据库提供的对象存储所使用的名称。

将请求添加到队列

创建 Queue 实例后,您可以使用其 pushRequest() 方法向其添加失败的请求:

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

const queue = new Queue('myQueueName');

self.addEventListener('fetch', (event) => {
  // Add in your own criteria here to return early if this
  // isn't a request that should use background sync.
  if (event.request.method !== 'POST') {
    return;
  }

  const bgSyncLogic = async () => {
    try {
      const response = await fetch(event.request.clone());
      return response;
    } catch (error) {
      await queue.pushRequest({request: event.request});
      return error;
    }
  };

  event.respondWith(bgSyncLogic());
});

添加到队列后,在 Service Worker 收到 sync 事件时,请求会自动重试,因为浏览器会认为网络已经恢复。不支持 BackgroundSync API 的浏览器会在每次 Service Worker 启动时重试请求,虽然重试失败的请求的效率较低,但却是一种回退。

正在测试 workbox-background-sync

测试后台同步行为可能比较复杂,但可以在 Chrome 开发者工具中完成。当前的最佳方法如下所示:

  1. 加载一个注册 Service Worker 的页面。
  2. 关闭计算机的网络连接或关闭网络服务器。请勿使用 Chrome 开发者工具中的离线切换开关!离线复选框仅影响来自页面的请求,但 Service Worker 请求将继续通过。
  3. 发出应使用 workbox-background-sync 加入队列的网络请求。您可以在 Chrome DevTools > Application > IndexedDB > workbox-background-sync > requests 中查看已排入队列的请求。
  4. 现在,您可以恢复网络连接或重新开启网络服务器。
  5. 通过转到 Chrome DevTools > Application > Service Workers 强制执行提前 sync 事件。输入 workbox-background-sync:<your queue name> 的标记名称,其中 <your queue name> 是您设置的队列名称。
  6. 点击“同步”按钮。
    Chrome 开发者工具应用面板中的后台同步实用程序的屏幕截图。为“workbox-background-sync”模块的“myQueueName”队列指定了同步事件。
  7. 您现在应该会看到之前失败的网络请求已进行重试和处理。这样一来,IndexedDB 存储区应该为空,因为请求已成功重放。

总结

使用 workbox-background-sync 重试失败的网络请求可以有效提升应用的用户体验和可靠性,例如允许用户重新提交失败的 API 请求,这样他们就不会丢失想要发送到 API 的数据。还可用于填补您自己的数据缺口,例如分析。实际上,workbox-google-analytics 模块会在后台使用 workbox-background-sync 重试失败的请求,以将数据发送到 Google Analytics(分析)。

无论您在何种使用场景下,workbox-background-sync 都能简化此类任务,提升您的开发者体验,并让您有更多机会改进 Web 应用的用户体验和功能。