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)問題~~