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

当您向网络服务器发出请求时,可能会发生故障。这可能是因为用户已断开连接,或者远程服务器已关闭。

虽然本文档主要侧重于介绍如何处理 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 应用于将 POST 请求与检索 JSON 数据的 API 路由匹配的路由。如果用户处于离线状态,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 开发者工具应用面板中后台同步实用程序的屏幕截图。为“myQueueName”队列指定了同步事件对于“workbox-background-sync”模块。
  7. 您现在应该会看到之前失败的网络请求重试并完成。因此,IndexedDB 存储区应该为空,因为请求已成功重放。

总结

使用 workbox-background-sync 重试失败的网络请求是提升用户体验和提升应用可靠性的好方法,例如允许用户重新提交失败的 API 请求,以免丢失想要发送到 API 的数据。它还可以用来填补您自己的数据缺口,例如分析。事实上,workbox-google-analytics 模块在后台使用 workbox-background-sync 来重试失败的请求,以便向 Google Analytics 发送数据。

无论您的使用情形是什么,workbox-background-sync 都能简化此类任务,为您提升开发者体验并为您提供更多机会来提升 Web 应用的用户体验和功能。