Service Worker 中的 API
Service Worker 静态路由 API
发布于 更新于
Service Worker 静态路由 API 让 service worker 在安装时声明哪些请求应由浏览器直接从网络或缓存获取,而不必为取回它们而运行 worker。声明的形式是在 install 处理器中传给 event.addRoutes() 的一组规则,每条规则把一个针对请求的条件与响应应当来自的来源配成一对。
addRoutes(routerRules)routerRules 是单个规则对象或由它们组成的数组,方法返回一个以 undefined 兑现的 promise。该方法位于 InstallEvent 上,因此可从 install 处理器访问,一组规则也就属于安装它的那个 worker 版本。规范指出 event.addRoutes(rules) 默认延长事件的生命周期,就像调用了 event.waitUntil(promise) 一样。
各引擎支持情况
Section titled “各引擎支持情况”BCD api.InstallEvent.addRoutes 记录了从 Chrome 123 和 Safari 27 起的支持,并镜像到它列出的基于 Chromium 的浏览器与 Safari 衍生版本;Firefox 没有支持,BCD 指向 Mozilla bug 1855580 说明实现状态。Chrome 的发布文章把该 API 描述为从 Chrome 123 起可用,之前自 Chrome 116 起以 registerRouter() 之名进行过源试用,该方法被这篇文章标记为已弃用,计划在 Chrome 125 中移除。
一条规则是 { condition, source }。下面这些条件键来自 MDN 的 addRoutes() 参考页;当一个条件中同时出现多个键时,资源必须满足全部条件才匹配该规则。
| 条件键 | 取值 | 匹配什么 |
|---|---|---|
urlPattern |
一个 URLPattern 实例,或可传入其构造函数的输入模式 |
匹配规则的那些 URL。不允许正则捕获组,因此 URLPattern.hasRegExpGroups 必须为 false。 |
requestMethod |
字符串,如 "get"、"put"、"head" |
发送请求所用的 HTTP 方法。 |
requestMode |
字符串,如 "same-origin"、"no-cors"、"cors" |
请求具有的模式。 |
requestDestination |
字符串,如 "audio"、"document"、"script"、"worker" |
请求的目标,即请求的内容类型。 |
runningStatus |
"running" 或 "not-running" |
service worker 所需的运行状态。 |
or |
条件对象数组 | 其中一组嵌套条件。or 内的条件与其他条件互斥。 |
not |
一个条件对象 | 必须明确不被满足的条件。not 内的条件与其他条件互斥。 |
source 是一个枚举值或一个对象。MDN 列出的枚举值为 "cache"、"network"、"fetch-event" 与 "race-network-and-fetch-handler",最后一个会同时尝试网络与 fetch 事件处理器,并采用先完成的那一个。MDN 把 "fetch-event" 与 runningStatus 条件搭配使用:worker 运行时经由它加载资源,不运行时回退到网络上的静态路由。对象形式携带单个 cacheName 属性来指名一个缓存;MDN 指出如果该缓存不存在,浏览器会改用网络,这样在网络可用时仍能取到所请求的资源。
MDN 列出的 TypeError 成因有:routerRules 内有无效的规则对象、worker 没有 fetch 事件处理器时 source 为 "fetch-event",以及 or 与另一类条件组合使用。
- 无效规则会让携带它的那次调用被拒绝,所以在上线前先校验生成出来的规则列表。
"fetch-event"与"race-network-and-fetch-handler"这两个来源依赖已注册的fetch处理器。addRoutes()算法 规定:当source为"fetch-event"或"race-network-and-fetch-handler",而 service worker 要处理的事件类型集合不包含fetch时,返回一个以TypeError拒绝的 promise。source为"network"、"cache"或cacheName对象的规则不在该步骤的指名范围内。- 条件中
or与同级键并列时必须改写为两条规则,每条对应一个分支并重复该同级键。MDN 自己给出的改写示例就把urlPattern与requestMethod配对了两次。 - 当 Check Router Registration Limit 算法(在 worker 现有路由规则列表的副本追加新规则后运行)返回 false 时,规范同样以
TypeError拒绝该 promise。
空的条件对象会被拒绝,而不是成为匹配一切的规则,这正是上面的第一条字符串。
下面这些示例是多数应用需要的形态:在某个路径上绕过 worker、在方法存在时才声明路由,以及用一个命名缓存服务图片扩展名。
在 worker 处于冷状态时把路径交给网络
Section titled “在 worker 处于冷状态时把路径交给网络”条件把 URL 模式与 runningStatus 组合起来,因此该规则在 service worker 不运行时生效,而这正是会付出启动开销的情形。
addEventListener('install', (event) => { event.addRoutes({ condition: { urlPattern: '/articles/*', runningStatus: 'not-running', }, source: 'network', });});worker 正在运行时这条规则不匹配,请求会到达 fetch 处理器,因此同一路径上的缓存优先策略在热导航中仍然适用。Chrome 的发布文章展示了镜像写法:runningStatus: "running" 配 source: "fetch-event"。
在方法存在时才声明路由,并带回退
Section titled “在方法存在时才声明路由,并带回退”addRoutes() 是事件对象上的方法,所以使用前可以检测。缺失分支不是降级模式:它就是静态路由出现之前 service worker 的行为,一切由 fetch 处理器决定。
addEventListener('install', (event) => { if (!('addRoutes' in event)) { // 该事件上没有 addRoutes():把路由交给 fetch 处理器。 return; } event .addRoutes([ { condition: { urlPattern: '/form/*', requestMethod: 'post' }, source: 'network' }, { condition: { requestDestination: 'font' }, source: { cacheName: 'fonts' } }, ]) .catch((error) => { console.error('static routes rejected, using the fetch handler instead', error); });});保留 catch。该方法以拒绝而不是同步抛出的方式报告失败,因此没有处理器的拒绝会让应用仅靠 fetch 处理器运行,并表现为一个未处理的 promise 拒绝。
用一个命名缓存服务两种图片扩展名
Section titled “用一个命名缓存服务两种图片扩展名”or 接受一组条件且与其他条件互斥,所以扩展名放进数组里,共享的来源留在数组外面。
addEventListener('install', (event) => { event.addRoutes({ condition: { or: [{ urlPattern: '*.png' }, { urlPattern: '*.jpg' }], }, source: { cacheName: 'pictures' }, });});若要把同样这两个模式收窄到 GET 请求,就写两条规则,各自带自己的 urlPattern 与 requestMethod,这也是 MDN 针对这种情况给出的改写方式。
Chrome DevTools 会显示浏览器实际注册了什么:Chrome 的发布文章指出,已注册的路由规则显示在 Application 面板的 Service Worker 标签中;在 Network 面板里,匹配到已注册规则的请求会在 size 列中标出,指针悬停时显示已注册的路由 ID。
- FetchEvent 与请求路由
- Service worker 缓存策略
- NavigationPreloadManager
- Service worker 生命周期
- InstallEvent: addRoutes() method(developer.mozilla.org)
- Service Workers: the addRoutes() method(w3c.github.io)
- Use the Service Worker Static Routing API to bypass the service worker for specific paths(developer.chrome.com)
规范
| 规范 | 状态 |
|---|---|
| Service Workers: the addRoutes() method | W3C 草案 |