Service Worker 可以拦截对页面的网络请求。它可能会响应 缓存内容、来自网络的内容或生成的内容 Service Worker 中的资源。
workbox-routing
是一个模块,可让您轻松地实现“路由”向 提供响应的各种不同函数。
如何执行路由
当网络请求导致 Service Worker 提取事件时,workbox-routing
将使用提供的路由和处理程序响应请求。
上述内容需要注意的主要事项包括:
请求的方法很重要。默认情况下,系统会为
GET
请求。如果您希望拦截其他类型的请求,则需要 以指定方法。路由注册的顺序很重要。如果有多个路由 可以处理请求的 Route,最先注册的 Route 将用于响应请求。
注册路线有几种方法:您可以使用回调、常规的 表达式或路由实例。
路由中的匹配和处理
“路线”只不过是两个函数:“匹配”函数 以确定路线是否与请求和“订单处理”相匹配函数, 它应处理请求并给出响应
Workbox 附带一些帮助程序,可用于对 但是,如果您发现自己想要不同的行为, 自定义匹配和处理程序函数是最佳选择。
答 匹配回调函数 传递一个 ExtendableEvent
、 Request
和 URL
对象 匹配。举一个简单的例子,您可以匹配 具体网址,例如:
const matchCb = ({url, request, event}) => { return url.pathname === '/special/url'; };
大多数用例都可以通过检查 / 测试 url
或 request
。
答 handler 回调函数 将获得 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
的 promise。在本课中, 我们使用的是 async
和 await
。 在后台,返回的 Response
值会封装在 promise 中。
您可以按如下方式注册这些回调:
import {registerRoute} from 'workbox-routing'; registerRoute(matchCb, handlerCb);
唯一的限制是,“匹配”回调必须同步返回一个 True 值,就无法执行任何异步工作。原因就在于 Router
必须同步响应提取事件或允许掉落 直到出现其他提取事件
通常,“处理程序”回调将使用所提供的策略之一 按workbox-strategies,如下所示:
import {registerRoute} from 'workbox-routing'; import {StaleWhileRevalidate} from 'workbox-strategies'; registerRoute(matchCb, new StaleWhileRevalidate());
在本页中,我们将重点介绍workbox-routing
, 详细了解工作箱策略方面的这些策略。
如何注册正则表达式路由
常见做法是使用正则表达式,而不是“匹配”回调。 借助 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
如果您确实需要这种行为,只需确保常规 匹配网址的开头。如果我们想将 请求 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
如果您想同时匹配本地和第三方,可以使用通配符 放在正则表达式的开头,但在使用时应格外小心 以确保它不会导致您的 Web 应用出现意外行为。
如何注册导航路线
如果您的网站是单页应用,您可以使用 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);
唯一需要注意的是,如果两个网址都存在一个网址,则 denylist
将胜出 allowlist
和 denylist
。
设置默认处理程序
如果您想提供一个“处理程序”对于与路由不匹配的请求 可以设置默认处理程序
import {setDefaultHandler} from 'workbox-routing'; setDefaultHandler(({url, event, params}) => { // ... });
设置 Catch 处理程序
如果您的任何路由引发错误,您可以捕获并 通过设置 catch 处理程序来妥善降级。
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
,突出显示正在处理的网址 自动同步。
如果您需要更详细的信息,可以将日志级别设置为 debug
, 查看未由路由器处理的请求的日志。请参阅我们的 调试指南,详细了解 设置日志级别
高级用法
想要更好地控制何时为 Workbox Router 提供 您可以创建自己的 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 可让您轻松创建 与浏览器匹配的workbox-routing.Route
[导航请求]https://developers.google.com/web/fundamentals/primers/service-workers/high-performance-loading#first_what_are_navigation_requests
。
它只会匹配符合以下条件的传入请求: 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
部分。注意:在运行实验的过程中,系统可能会针对每个目标网址评估这些正则表达式 导航。避免使用 复杂的正则表达式, 否则用户在浏览您的网站时可能会遇到延迟
constructor
函数如下所示:(handler: RouteHandler, options?: NavigationRouteMatchOptions) => {...}
-
回调 函数,该函数会返回 Promise 并产生 Response。
-
-
HTTPMethod
-
void
setCatchHandler
函数如下所示:(handler: RouteHandler) => {...}
-
回调 用于返回解析为 Response 的 Promise 的函数
-
NavigationRouteMatchOptions
属性
-
RegExp[] 可选
-
RegExp[] 可选
RegExpRoute
RegExpRoute 可让您轻松创建基于 workbox-routing.Route
。
对于同源请求,正则表达式只需要匹配网址的一部分。对于 针对第三方服务器发送请求,您必须定义一个与 网址的开头。
属性
- 构造函数
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 并产生 Response。
- method
HTTPMethod(可选)
-
- catchHandler
- handler
- method
HTTPMethod
- setCatchHandler
void
setCatchHandler
函数如下所示:(handler: RouteHandler) => {...}
- handler
回调 用于返回解析为 Response 的 Promise 的函数
-
Route
Route
由一对回调函数“match”组成和“handler”。 “匹配”回调来确定是否应将路线用于“处理”一 通过返回一个非 Falsy 值(如果可以)请求。“处理程序”回拨 如果存在匹配项,则调用该 promise,并且应返回一个可解析的 promise 转换为 Response
。
属性
- 构造函数
void
Route 类的构造函数。
constructor
函数如下所示:(match: RouteMatchCallback, handler: RouteHandler, method?: HTTPMethod) => {...}
-
一个回调函数,用于确定路线是否与指定的 通过返回非 falsy 值来触发
fetch
事件。 - handler
回调 函数,该函数返回解析为 Response 的 Promise。
- method
HTTPMethod(可选)
- 返回
-
- catchHandler
- handler
- method
HTTPMethod
- setCatchHandler
void
setCatchHandler
函数如下所示:(handler: RouteHandler) => {...}
- handler
回调 用于返回解析为 Response 的 Promise 的函数
-
Router
该路由器可以用来处理FetchEvent
使用一个或多个 workbox-routing.Route
,如果满足以下条件,则返回 Response
: 存在匹配的路由。
如果没有与给定请求匹配的路由,路由器将使用“default” 处理程序。
如果匹配的路由抛出错误,路由器将使用“catch” 处理程序(如果定义了一个处理程序,以优雅地处理问题并使用 请求。
如果某个请求与多个路由匹配,则最早的注册路由将 用于响应请求。
属性
- 构造函数
void
初始化新的路由器。
constructor
函数如下所示:() => {...}
- 返回
-
- 路由
Map<HTTPMethodRoute[]>
- addCacheListener
void
为要从窗口中缓存的网址添加消息事件监听器。 这对于在调用 Service Worker 开始控制它。
从窗口发送的消息数据的格式应如下所示。 其中
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) => {...}
- 返回
对象
一个具有
route
和params
属性的对象。 如果找到了匹配的路由或undefined
,则会填充这些字段 否则。
-
- handleRequest
void
将路由规则应用于 FetchEvent 对象,以从 相应 Route 的处理程序。
handleRequest
函数如下所示:(options: object) => {...}
- 选项
对象
- 事件
ExtendableEvent
触发 请求。
- request
请求
要处理的请求。
-
- 返回
Promise<Response>
如果 就可以处理该请求如果没有匹配的 路线,并且没有
defaultHandler
,则返回undefined
。
-
- registerRoute
void
向路由器注册路由。
registerRoute
函数如下所示:(route: Route) => {...}
- 路线
要注册的路线。
-
- setCatchHandler
void
如果 Route 在处理请求时抛出错误,此
handler
将调用 ,并有机会给出响应。setCatchHandler
函数如下所示:(handler: RouteHandler) => {...}
- handler
回调 函数,该函数返回 Promise 并产生 Response。
-
- setDefaultHandler
void
定义在没有显式路由时调用的默认
handler
与传入请求匹配。每个 HTTP 方法(“GET”、“POST”等)都有自己的默认处理程序。
如果没有默认处理程序,不匹配的请求将处理 就像没有 Service Worker 一样。
setDefaultHandler
函数如下所示:(handler: RouteHandler, method?: HTTPMethod) => {...}
- handler
回调 函数,该函数返回 Promise 并产生 Response。
- method
HTTPMethod(可选)
-
- unregisterRoute
void
向路由器取消注册路由。
unregisterRoute
函数如下所示:(route: Route) => {...}
- 路线
要取消注册的路由。
-
方法
registerRoute()
workbox-routing.registerRoute(
capture: string | RegExp | RouteMatchCallback | Route,
handler?: RouteHandler,
method?: HTTPMethod,
)
使用缓存轻松注册正则表达式、字符串或函数 单例路由器实例。
此方法会为您生成一个 Route(如果需要),并且 调用 workbox-routing.Router#registerRoute
。
参数
- 截图/录像
string |正则表达式 |RouteMatchCallback |路线
如果捕获参数为
Route
,则将忽略所有其他参数。 - handler
RouteHandler(可选)
- method
HTTPMethod(可选)
返回
-
生成的
Route
。
setCatchHandler()
workbox-routing.setCatchHandler(
handler: RouteHandler,
)
如果 Route 在处理请求时抛出错误,此 handler
将调用 ,并有机会给出响应。
参数
- handler
回调 函数,该函数会返回 Promise 并产生 Response。
setDefaultHandler()
workbox-routing.setDefaultHandler(
handler: RouteHandler,
)
定义在没有显式路由时调用的默认 handler
与传入请求匹配。
如果没有默认处理程序,不匹配的请求将处理 就像没有 Service Worker 一样。
参数
- handler
回调 函数,该函数会返回 Promise 并产生 Response。