Service Worker 可攔截網頁的網路要求。它可能會以快取內容、網路內容或服務工作站產生的內容對瀏覽器做出回應。
workbox-routing
模組可讓您輕鬆將這些要求「轉送」至提供回應的不同函式。
轉送執行方式
當網路要求造成 Service Worker 擷取事件時,workbox-routing
會嘗試使用提供的路徑和處理常式回應要求。
上文需要注意的是:
要求的方法相當重要。根據預設,路徑會註冊用於
GET
要求。如要攔截其他類型的要求,您需要指定方法。路線登錄順序相當重要。如果註冊了多個路徑可以處理要求,則優先登錄的路徑會用來回應要求。
註冊路徑的幾種方式如下:您可以使用回呼、規則運算式或路徑執行個體。
在路徑中比對及處理
工作箱中的「route」是指兩個函式,兩者都是「matching」函式,用於判斷路徑是否應符合要求,而「處理」函式則應處理要求並回應。
Workbox 提供了一些輔助程式,可為您執行比對和處理作業,但如果發現自己需要不同的行為,請撰寫自訂比對和處理常式函式。
比對回呼函式會傳遞 ExtendableEvent
、Request
及可傳回傾斜值比對的 URL
物件。舉個簡單的例子,您可以比對特定網址,如下所示:
const matchCb = ({url, request, event}) => {
return url.pathname === '/special/url';
};
大部分用途都能透過檢查 / 測試 url
或 request
來涵蓋。
處理常式回呼函式會具有相同的 ExtendableEvent
、Request
和 URL
物件與 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
的承諾。在此範例中,我們使用的是 async
和 await
。實際上,回傳的 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
或自己的安裝步驟要求快取網頁。)
根據預設,這個屬性會回應「所有」瀏覽要求。如要限制網址只能回應部分網址,可以使用 allowlist
和 denylist
選項來限制哪些網頁與這個路徑相符。
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);
請注意,如果網址同時位於 allowlist
和 denylist
中,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_requests
的 workbox-routing.Route
。
只會比對傳入的要求 (https://fetch.spec.whatwg.org/#concept-request-mode|mode
設為 navigate
)。
您可以選擇使用一或兩項 denylist
和 allowlist
參數,選擇僅將這條路徑套用至部分導航要求。
屬性
-
void
如果同時提供
denylist
和allowlist
,系統會優先採用denylist
,且要求不會與這個路徑相符。allowlist
和denylist
中的規則運算式會與串連的 [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) => {...}
-
這個回呼函式可以傳回 Promise,並在回應中產生回應。
-
-
HTTPMethod
-
void
setCatchHandler
函式如下所示:(handler: RouteHandler) => {...}
-
回呼函式可傳回 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 選用
-
returns
-
-
catchHandler
-
handler
-
相符項目
-
method
HTTPMethod
-
setCatchHandler
void
setCatchHandler
函式如下所示:(handler: RouteHandler) => {...}
-
handler
回呼函式可傳回 Promise 解析給回應
-
Route
Route
包含一組回呼函式「match」和「handler」。「match」回呼會判斷是否應使用路徑來「處理」要求,方法是在可能的情況下傳回非虛設值。如果有相符項目,系統會呼叫「處理常式」回呼,並應傳回會解析為 Response
的 Promise。
屬性
-
建構函式
void
Route 類別的建構函式。
constructor
函式如下所示:(match: RouteMatchCallback, handler: RouteHandler, method?: HTTPMethod) => {...}
-
相符項目
回呼函式,可傳回非虛構值,藉此判斷路徑是否與指定的
fetch
事件相符。 -
handler
回呼函式,可傳回 Promise 解析為回應。
-
method
HTTPMethod 選用
-
returns
-
-
catchHandler
-
handler
-
相符項目
-
method
HTTPMethod
-
setCatchHandler
void
setCatchHandler
函式如下所示:(handler: RouteHandler) => {...}
-
handler
回呼函式可傳回 Promise 解析給回應
-
Router
路由器可用來處理使用一或多個 workbox-routing.Route
的 FetchEvent
,並在有相符的路徑時以 Response
回應。
如果指定路徑沒有任何相符的路徑,則路由器會使用「預設」處理常式 (如已定義)。
如果相符的路徑擲回錯誤,路由器就會使用「catch」處理常式 (如已定義其處理常式),以便妥善處理問題並透過要求回應。
如果要求同時符合多條路徑,則會使用「最早」登錄的路徑來回應要求。
屬性
-
建構函式
void
初始化新的路由器。
constructor
函式如下所示:() => {...}
-
returns
-
-
路徑
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
物件
包含
route
和params
屬性的物件。 如果找到相符的路徑,系統就會填入這些路線,否則就會填入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
。
參數
-
擷取
string | RegExp | RouteMatchCallback | Route
如果擷取參數是
Route
,系統將忽略所有其他引數。 -
handler
RouteHandler 選用
-
method
HTTPMethod 選用
傳回
-
產生的
Route
。
setCatchHandler()
workbox-routing.setCatchHandler(
handler: RouteHandler,
)
如果路徑在處理要求時擲回錯誤,系統會呼叫這個 handler
,並有機會提供回應。
參數
-
handler
這個回呼函式可以傳回 Promise,並在回應中產生回應。
setDefaultHandler()
workbox-routing.setDefaultHandler(
handler: RouteHandler,
)
定義預設 handler
,在沒有明確符合傳入要求的路徑時呼叫。
如果沒有預設處理常式,不相符的要求就會傳送至網路,就像沒有任何 Service Worker 一樣。
參數
-
handler
這個回呼函式可以傳回 Promise,並在回應中產生回應。