恢復連線後重試要求

向網路伺服器發出要求時,可能會失敗。這可能是因為使用者已中斷連線,或是遠端伺服器當機。

雖然本說明文件的重點在於處理服務工作站中的 GET 要求,但其他方法 (例如 POSTPUTDELETE) 可能還有一些問題。這些方法經常用於與後端 API 通訊,以提供網頁應用程式資料。當這些要求在沒有 Service Worker 的情況下失敗時,必須讓使用者在恢復連線時手動重試,使用者也不必記得這樣做。

如果這是您的應用程式說明,且其中有 Service Worker 的混合情形,您最好在使用者恢復連線時重試傳送失敗的要求。BackgroundSync API 可以提供此問題的解決方案。當 Service Worker 偵測到網路要求失敗時,只要註冊即可在瀏覽器偵測到連線已傳回時接收 sync 事件。即使使用者已離開註冊該事件的頁面,系統仍會傳送 sync 事件,因此比起其他重試失敗要求的方法,這麼做更有效率。

Workbox 透過 workbox-background-sync 模組抽象化這個 API,讓 BackgroundSync API 可以與其他 Workbox 模組搭配使用。並針對尚未支援 BackgroundSync 的瀏覽器實作備用策略。

基本用法

BackgroundSyncPlugin 是從 workbox-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 資料。如果使用者處於離線狀態,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,則每次服務工作處理程序啟動時都會重試要求,這種做法雖然重試失敗的要求,但提供排序備用的替代方案。

正在測試 workbox-background-sync

測試背景同步行為可能有些困難,但可以在 Chrome 開發人員工具中完成。目前的最佳做法如下:

  1. 載入用來註冊 Service Worker 的頁面。
  2. 關閉電腦的網路連線,或是關閉網路伺服器。請勿使用 Chrome 開發人員工具中的離線切換按鈕!離線核取方塊只會影響網頁發出的要求,但服務工作處理程序的要求會繼續處理。
  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 都能簡化這類型的工作、改善開發人員體驗,讓您有更多機會可以改善網頁應用程式的使用者體驗和功能。