工作箱路由

Service Worker 可攔截網頁的網路要求。它可能會以快取內容、網路內容或服務工作站產生的內容對瀏覽器做出回應。

workbox-routing 模組可讓您輕鬆將這些要求「轉送」至提供回應的不同函式。

轉送執行方式

當網路要求造成 Service Worker 擷取事件時,workbox-routing 會嘗試使用提供的路徑和處理常式回應要求。

工作站轉送圖表

上文需要注意的是:

  • 要求的方法相當重要。根據預設,路徑會註冊用於 GET 要求。如要攔截其他類型的要求,您需要指定方法。

  • 路線登錄順序相當重要。如果註冊了多個路徑可以處理要求,則優先登錄的路徑會用來回應要求。

註冊路徑的幾種方式如下:您可以使用回呼、規則運算式或路徑執行個體。

在路徑中比對及處理

工作箱中的「route」是指兩個函式,兩者都是「matching」函式,用於判斷路徑是否應符合要求,而「處理」函式則應處理要求並回應。

Workbox 提供了一些輔助程式,可為您執行比對和處理作業,但如果發現自己需要不同的行為,請撰寫自訂比對和處理常式函式。

比對回呼函式會傳遞 ExtendableEventRequest 及可傳回傾斜值比對的 URL 物件。舉個簡單的例子,您可以比對特定網址,如下所示:

const matchCb = ({url, request, event}) => {
  return url.pathname === '/special/url';
};

大部分用途都能透過檢查 / 測試 urlrequest 來涵蓋。

處理常式回呼函式會具有相同的 ExtendableEventRequestURL 物件params 值,也就是「match」函式傳回的值。

const handlerCb = async ({url, request, event, params}) => {
  const response = await fetch(request);
  const responseBody = await response.text();
  return new Response(`${responseBody} <!-- Look Ma. Added Content. -->`, {
    headers: response.headers,
  });
};

您的處理常式必須傳回會解析為 Response 的承諾。在此範例中,我們使用的是 asyncawait。實際上,回傳的 Response 值會納入承諾內容中。

您可以註冊這些回呼,如下所示:

import {registerRoute} from 'workbox-routing';

registerRoute(matchCb, handlerCb);

唯一的限制是「比對」回呼「必須」同步傳回超值值,因此您無法執行任何非同步工作。這是因為 Router 必須同步回應擷取事件,或允許傳送至其他擷取事件。

在一般情況下,「handler」回呼會使用 workbox-Strategyies 提供的其中一項策略,如下所示:

import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';

registerRoute(matchCb, new StaleWhileRevalidate());

本頁面將著重於 workbox-routing,但您可以進一步瞭解這些與工作相關的策略

如何註冊規則運算式路徑

常見的做法是使用規則運算式,而不是「match」回呼。Workbox 提供簡單的實作方式,如下所示:

import {registerRoute} from 'workbox-routing';

registerRoute(new RegExp('/styles/.*\\.css'), handlerCb);

針對來自相同來源的要求,只要要求的網址與規則運算式相符,這個規則運算式就會進行比對。

  • https://example.com/styles/main.css
  • https://example.com/styles/nested/file.css
  • https://example.com/nested/styles/directory.css

不過,如果是跨來源要求,規則運算式必須與網址開頭相符。這是因為您可能使用規則運算式 new RegExp('/styles/.*\\.css') 來比對第三方 CSS 檔案。

  • https://cdn.third-party-site.com/styles/main.css
  • https://cdn.third-party-site.com/styles/nested/file.css
  • https://cdn.third-party-site.com/nested/styles/directory.css

如果「did」想要這個行為,您只需確保規則運算式與網址開頭相符即可。如要比對 https://cdn.third-party-site.com 的要求,可以使用規則運算式 new RegExp('https://cdn\\.third-party-site\\.com.*/styles/.*\\.css')

  • https://cdn.third-party-site.com/styles/main.css
  • https://cdn.third-party-site.com/styles/nested/file.css
  • https://cdn.third-party-site.com/nested/styles/directory.css

如果想同時比對本機和第三方,可以在規則運算式的開頭使用萬用字元,但請務必謹慎行事,確保您的網站不會導致網頁應用程式發生非預期行為。

如何註冊導覽路徑

如果您的網站是單一頁面應用程式,可以使用 NavigationRoute 傳回所有導覽要求的特定回應。

import {createHandlerBoundToURL} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';

// This assumes /app-shell.html has been precached.
const handler = createHandlerBoundToURL('/app-shell.html');
const navigationRoute = new NavigationRoute(handler);
registerRoute(navigationRoute);

每當使用者在瀏覽器中前往您的網站,頁面要求就會成為瀏覽要求,並傳送快取頁面 /app-shell.html。 (注意:您應該透過 workbox-precaching 或自己的安裝步驟要求快取網頁。)

根據預設,這個屬性會回應「所有」瀏覽要求。如要限制網址只能回應部分網址,可以使用 allowlistdenylist 選項來限制哪些網頁與這個路徑相符。

import {createHandlerBoundToURL} from 'workbox-precaching';
import {NavigationRoute, registerRoute} from 'workbox-routing';

// This assumes /app-shell.html has been precached.
const handler = createHandlerBoundToURL('/app-shell.html');
const navigationRoute = new NavigationRoute(handler, {
  allowlist: [new RegExp('/blog/')],
  denylist: [new RegExp('/blog/restricted/')],
});
registerRoute(navigationRoute);

請注意,如果網址同時位於 allowlistdenylist 中,denylist 將會勝出。

設定預設處理常式

如果您想為不符合路徑的要求提供「處理常式」,可以設定預設處理常式。

import {setDefaultHandler} from 'workbox-routing';

setDefaultHandler(({url, event, params}) => {
  // ...
});

設定接收處理常式

萬一任何路徑擲回錯誤,您可以設定擷取處理常式,以便順利擷取並降級。

import {setCatchHandler} from 'workbox-routing';

setCatchHandler(({url, event, params}) => {
  ...
});

定義非 GET 要求的路徑

根據預設,所有路徑都會假設為 GET 要求。

如要轉送其他要求 (例如 POST 要求),您必須在註冊路線時定義方法,如下所示:

import {registerRoute} from 'workbox-routing';

registerRoute(matchCb, handlerCb, 'POST');
registerRoute(new RegExp('/api/.*\\.json'), handlerCb, 'POST');

路由器記錄

您可以使用 workbox-routing 的記錄判斷要求的流程,並醒目顯示要透過 Workbox 處理的網址。

轉送記錄

如果您需要更詳細的資訊,可以將記錄層級設為 debug,以查看路由器未處理要求的相關記錄。如要進一步瞭解如何設定記錄層級,請參閱偵錯指南

偵錯和記錄轉送訊息

進階用法

如要進一步控管向 Workbox 路由器發出要求的時間,您可以建立自己的 Router 執行個體,並在每次使用路由器回應要求時呼叫 handleRequest() 方法。

import {Router} from 'workbox-routing';

const router = new Router();

self.addEventListener('fetch', event => {
  const {request} = event;
  const responsePromise = router.handleRequest({
    event,
    request,
  });
  if (responsePromise) {
    // Router found a route to handle the request.
    event.respondWith(responsePromise);
  } else {
    // No route was found to handle the request.
  }
});

直接使用 Router 時,也需要使用 Route 類別或任何擴充類別來登錄路徑。

import {Route, RegExpRoute, NavigationRoute, Router} from 'workbox-routing';

const router = new Router();
router.registerRoute(new Route(matchCb, handlerCb));
router.registerRoute(new RegExpRoute(new RegExp(...), handlerCb));
router.registerRoute(new NavigationRoute(handlerCb));

類型

NavigationRoute

NavigationRoute 可讓您輕鬆建立符合瀏覽器 [導覽要求]https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requestsworkbox-routing.Route

只會比對傳入的要求 (https://fetch.spec.whatwg.org/#concept-request-mode|mode 設為 navigate)。

您可以選擇使用一或兩項 denylistallowlist 參數,選擇僅將這條路徑套用至部分導航要求。

屬性

  • 建構函式

    void

    如果同時提供 denylistallowlist,系統會優先採用 denylist,且要求不會與這個路徑相符。

    allowlistdenylist 中的規則運算式會與串連的 [pathname]https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/pathname 和 [search]https://developer.mozilla.org/en-US/docs/Web/API/HTMLHyperlinkElementUtils/search 部分 (要求網址) 進行比對。

    注意:在導覽期間,系統可能會根據每個到達網頁網址評估這些規則運算式。請避免使用複雜 RegExps,否則使用者在瀏覽您的網站時可能會遇到延遲。

    constructor 函式如下所示:

    (handler: RouteHandler,options?: NavigationRouteMatchOptions)=> {...}

  • catchHandler
  • 相符項目
  • method

    HTTPMethod

  • setCatchHandler

    void

    setCatchHandler 函式如下所示:

    (handler: RouteHandler)=> {...}

    • handler

      回呼函式可傳回 Promise 解析給回應

NavigationRouteMatchOptions

屬性

  • 加入許可清單

    RegExp[] 選填

  • 拒絕清單

    RegExp[] 選填

RegExpRoute

您可以使用 RegExpRoute 輕鬆建立以規則運算式為基礎的 workbox-routing.Route

對於相同來源的要求,RegExp 只需要與部分網址相符。針對對第三方伺服器提出的要求,您必須定義與網址開頭相符的 RegExp。

屬性

  • 建構函式

    void

    如果規則運算式包含 [擷取群組]https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#grouping-back-references,擷取的值會傳遞至 workbox-routing~handlerCallback params 引數。

    constructor 函式如下所示:

    (regExp: RegExp,handler: RouteHandler,method?: HTTPMethod)=> {...}

    • regExp

      RegExp

      用來比對網址的規則運算式。

    • handler

      這個回呼函式可以傳回 Promise,並在回應中產生回應。

    • method

      HTTPMethod 選用

  • catchHandler
  • 相符項目
  • method

    HTTPMethod

  • setCatchHandler

    void

    setCatchHandler 函式如下所示:

    (handler: RouteHandler)=> {...}

    • handler

      回呼函式可傳回 Promise 解析給回應

Route

Route 包含一組回呼函式「match」和「handler」。「match」回呼會判斷是否應使用路徑來「處理」要求,方法是在可能的情況下傳回非虛設值。如果有相符項目,系統會呼叫「處理常式」回呼,並應傳回會解析為 Response 的 Promise。

屬性

Router

路由器可用來處理使用一或多個 workbox-routing.RouteFetchEvent,並在有相符的路徑時以 Response 回應。

如果指定路徑沒有任何相符的路徑,則路由器會使用「預設」處理常式 (如已定義)。

如果相符的路徑擲回錯誤,路由器就會使用「catch」處理常式 (如已定義其處理常式),以便妥善處理問題並透過要求回應。

如果要求同時符合多條路徑,則會使用「最早」登錄的路徑來回應要求。

屬性

  • 建構函式

    void

    初始化新的路由器。

    constructor 函式如下所示:

    ()=> {...}

  • 路徑

    Map<HTTPMethodRoute[]>

  • addCacheListener

    void

    為網址新增訊息事件監聽器,以便從視窗快取網址。 如要在服務工作站開始控管資源前快取頁面的資源,這項功能非常實用。

    從視窗傳送的訊息資料應採用以下格式。其中 urlsToCache 陣列包含網址字串或網址字串 + requestInit 物件的陣列 (與傳送至 fetch() 時相同)。

    {
      type: 'CACHE_URLS',
      payload: {
        urlsToCache: [
          './script1.js',
          './script2.js',
          ['./script3.js', {mode: 'no-cors'}],
        ],
      },
    }
    

    addCacheListener 函式如下所示:

    ()=> {...}

  • addFetchListener

    void

    新增擷取事件監聽器,以便在路徑符合事件要求時回應事件。

    addFetchListener 函式如下所示:

    ()=> {...}

  • findMatchingRoute

    void

    依據已註冊路徑清單檢查要求和網址 (以及選擇性的事件),如果比對相符,會傳回對應的路徑以及比對後產生的任何參數。

    findMatchingRoute 函式如下所示:

    (options: RouteMatchCallbackOptions)=> {...}

    • returns

      物件

      包含 routeparams 屬性的物件。 如果找到相符的路徑,系統就會填入這些路線,否則就會填入 undefined

  • handleRequest

    void

    將轉送規則套用至 FetchEvent 物件,以便從適當的 Route 處理常式取得回應。

    handleRequest 函式如下所示:

    (options: object)=> {...}

    • 選項

      物件

      • event

        ExtendableEvent

        觸發要求的事件。

      • 申請。

        要求

        要處理的要求。

    • returns

      Promise<Response>

      如果註冊的路徑可以處理要求,系統就會傳回承諾。如果沒有相符的路徑,且沒有 defaultHandler,會傳回 undefined

  • registerRoute

    void

    向路由器註冊路徑。

    registerRoute 函式如下所示:

    (route: Route)=> {...}

    • 路徑

      註冊路徑。

  • setCatchHandler

    void

    如果路徑在處理要求時擲回錯誤,系統會呼叫這個 handler,並有機會提供回應。

    setCatchHandler 函式如下所示:

    (handler: RouteHandler)=> {...}

    • handler

      這個回呼函式可以傳回 Promise,並在回應中產生回應。

  • setDefaultHandler

    void

    定義預設 handler,在沒有明確符合傳入要求的路徑時呼叫。

    每個 HTTP 方法 (「GET」、「POST」等) 都有專屬的預設處理常式。

    如果沒有預設處理常式,不相符的要求就會傳送至網路,就像沒有任何 Service Worker 一樣。

    setDefaultHandler 函式如下所示:

    (handler: RouteHandler,method?: HTTPMethod)=> {...}

    • handler

      這個回呼函式可以傳回 Promise,並在回應中產生回應。

    • method

      HTTPMethod 選用

  • unregisterRoute

    void

    取消註冊路由器的路徑。

    unregisterRoute 函式如下所示:

    (route: Route)=> {...}

    • 路徑

      取消註冊的路徑。

方法

registerRoute()

workbox-routing.registerRoute(
  capture: string|RegExp|RouteMatchCallback|Route,
  handler?: RouteHandler,
  method?: HTTPMethod,
)

透過快取策略,輕鬆註冊 RegExp、字串或函式至單例路由器執行個體。

這個方法會在必要時為您產生路徑,並呼叫 workbox-routing.Router#registerRoute

參數

傳回

setCatchHandler()

workbox-routing.setCatchHandler(
  handler: RouteHandler,
)

如果路徑在處理要求時擲回錯誤,系統會呼叫這個 handler,並有機會提供回應。

參數

  • handler

    這個回呼函式可以傳回 Promise,並在回應中產生回應。

setDefaultHandler()

workbox-routing.setDefaultHandler(
  handler: RouteHandler,
)

定義預設 handler,在沒有明確符合傳入要求的路徑時呼叫。

如果沒有預設處理常式,不相符的要求就會傳送至網路,就像沒有任何 Service Worker 一樣。

參數

  • handler

    這個回呼函式可以傳回 Promise,並在回應中產生回應。