【前-workbox-模塊4】workbox.routing

1、什么是Workbox Routing?

service worker可以攔截網(wǎng)頁的網(wǎng)絡(luò)請求,它可以把從網(wǎng)絡(luò)請求中緩存的或在Serv worker中請求獲取的內(nèi)容,返回給瀏覽器。也就是說瀏覽器不會再直接與服務(wù)器交互,轉(zhuǎn)而全權(quán)由service worker代理。

workbox-routing是一個模塊,可以很容易地將這些請求“路由”映射到不同的響應(yīng),并提供設(shè)置相應(yīng)策略的方法。

2、如何執(zhí)行routing

當(dāng)一個網(wǎng)絡(luò)請求觸發(fā)了service worker的fetch事件時,workbox-routing將嘗試使用提供的路由和處理程序響應(yīng)請求。


從上圖中,我們可以知道以下幾件重要的事情:

  • 請求的類型很重要。默認(rèn)情況下,路由已注冊了“GET”請求的事件監(jiān)聽。 如果開發(fā)者希望攔截其他類型的請求,則需要指定額外的方法。

  • 路由注冊的順序很重要。如果注冊了多個可以處理請求的路由,則首先注冊的路由將優(yōu)先響應(yīng)請求。

有幾種方法可以注冊路由,開發(fā)者可以使用回調(diào),正則表達(dá)式或路由實例,我們將在下面介紹每個實例。

3、路由的匹配和處理

workbox 的“路由傳入了兩個函數(shù):一個“匹配”函數(shù),用于確定路由是否應(yīng)該與請求匹配,一個“處理”函數(shù),它應(yīng)該處理請求并響應(yīng)。

Workbox提供了一些構(gòu)造器,它們將執(zhí)行匹配和處理,但如果想要不同的行為或響應(yīng),那么開發(fā)者可以編寫自定義匹配和處理函數(shù)。

匹配函數(shù)將被賦予FetchEvent和URL對象,開發(fā)者可以通過返回truthy值來匹配請求。 舉一個簡單的例子,匹配特定的URL,如下所示:

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

通過來檢查/測試url或event.request匹配的請求,可以涵蓋大多數(shù)情況。

“處理程序”也將被賦予URL和事件,可以確定如何響應(yīng),無論是來自網(wǎng)絡(luò),還是來自緩存,還是生成在service worker中。

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

handler必須返回一個處理response的promise方法,使用如下方法可以注冊這些回調(diào)

workbox.routing.registerRoute(matchCb, handlerCb);

唯一的限制是“匹配”必須同步返回一個truthy值,你不能執(zhí)行任何異步工作。 這樣做的原因是Router 必須同步響應(yīng)獲取事件或允許下發(fā)到其他的獲取事件。

“handler”回調(diào)應(yīng)該返回一個解析為Response的Promise。 響應(yīng)的來源取決于開發(fā)者,網(wǎng)絡(luò)緩存或service worker生成的響應(yīng)。

通常,“處理程序”回調(diào)將使用workbox-strategy提供的策略之一,如下所示:

workbox.routing.registerRoute(
  matchCb,
  workbox.strategies.staleWhileRevalidate()
);

在此本文中,我們將重點關(guān)注workbox-routing,但你可以在workbox.strategies上了解有關(guān)這些策略的更多信息。

3、如何注冊正則表達(dá)式路由

通常的做法是使用正則表達(dá)式而不是“匹配”回調(diào)。 Workbox使這很容易實現(xiàn),如下所示:

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

對于同源的請求,只要請求的URL與正則表達(dá)式匹配,此正則表達(dá)式就會匹配。


上述三個路由都將被匹配

但是,對于跨域請求,正則表達(dá)式必須使用完整的URL開頭匹配。 這樣做的原因是,使用正則表達(dá)式new RegExp('/ styles /.* \ .css')不太可能與第三方CSS文件完全匹配。

如果你想匹配本地和第三方,可以在正則表達(dá)式的開頭使用通配符,但這應(yīng)該謹(jǐn)慎進(jìn)行,以確保它不會在Web應(yīng)用程序中導(dǎo)致意外行為。

4、如何注冊 Navigation Route

如果站點是單頁面應(yīng)用程序,則可以使用NavigationRoute返回所有導(dǎo)航請求的特定響應(yīng)。

workbox.routing.registerNavigationRoute('/single-page-app.html');

每當(dāng)用戶在瀏覽器中訪問你的網(wǎng)站時,該頁面的請求將成為導(dǎo)航請求,并將在緩存頁面“/single-page-app.html”中提供。 (注意:你應(yīng)該通過workbox-precaching或通過自己的安裝步驟緩存頁面)。

默認(rèn)情況下,這將響應(yīng)所有導(dǎo)航請求,如果您希望將其限制為響應(yīng)URL的子集,則可以使用白名單和黑名單選項來限制哪些頁面將匹配此路由。

workbox.routing.registerNavigationRoute('/single-page-app.html', {
  whitelist: [
    new RegExp('/blog/')
  ],
  blacklist: [
    new RegExp('/blog/restricted/'),
  ]
});

唯一需要注意的是,如果URL同時位于白名單和黑名單中,黑名單優(yōu)先。

5、設(shè)置默認(rèn)的處理函數(shù)

如果要為與路徑不匹配的請求提供“處理程序”,則可以設(shè)置默認(rèn)處理程序。

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

6、設(shè)置catch handler

如果您的任何路由拋出錯誤,您可以通過設(shè)置catch處理程序來優(yōu)雅地捕獲和下發(fā)。

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

7、定義非GET請求的路由

默認(rèn)情況下,所有路由都假定為“GET”請求。

如果您想路由其他請求,例如“POST”請求,則需要在注冊請求時定義方法,如下所示:

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

8、Router 日志

您應(yīng)該能夠使用來自workbox-routing的日志確定請求的流程,該日志將突出顯示通過Workbox處理的URL。

9、高級用法

如果您希望更好地控制何時向Workbox Router發(fā)出請求,您可以創(chuàng)建自己的路由器實例,并在需要使用路由器響應(yīng)請求時調(diào)用它的handleRequest()方法。

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

直接使用路由器時,您還需要使用Route類或任何擴(kuò)展類來注冊路由。

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

筆者個人訂閱號~歡迎小伙伴們關(guān)注


微信公眾號-感謝關(guān)注

若有疑問可以QQ聯(lián)系筆者,雖然不一定100%解決你的問題,但是可以交流探討一波:2276604211

順便打個廣告:如果有想入職中國銀聯(lián)上海技術(shù)開發(fā)的童鞋,也可以加上面的QQ資訊,筆者可以幫你回答一些相關(guān)問題~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容