路由请求
Workbox中的路由就是一个匹配请求的路由器,然后路由处理该请求(提供响应)的一个过程。
workbox-routing 匹配请求有三种方式:
- 字符串.
- 正则表达式.
- 回调函数.
我们将首先研究如何使用这三种方法进行匹配,然后继续讨论请求的处理,在请求中 handler 参数就是一个占位符。
字符串匹配
利用字符串来匹配很容易理解,但这并不是很最好匹配方式。
请求地址会和路由字符串进行比较,如果相等,路由会处理该请求。
那么,我们来定义一个字符串路由 “/logo.png”,像下面这样:
workbox.routing.registerRoute(
'/logo.png',
handler
);
需要注意的是,上面代码的请求匹配只能匹配网站自己的域名地址,如果你有其他域名的请求地址, https://some-other-origin.com/logo.png,那么将不会匹配到,因为大部分情况有会出现这种情况。你可以像下面的代码一样,定义全路径来匹配请求地址。
workbox.routing.registerRoute(
'https://some-other-origin.com/logo.png',
handler
);
正则表达式匹配
当你有一组地址需要路由来匹配的话,正则表达式匹配会是你最好的选择。
正则会判断你整个地址是否匹配,如果匹配,则会触发路由,这样代码有了很大的灵活性,如果想让路由匹配特定的文件后缀,可以写成下面这样:
workbox.routing.registerRoute(
new RegExp('\\.js$'),
jsHandler
);
workbox.routing.registerRoute(
new RegExp('\\.css$'),
cssHandler
);
或者,你可以写一个正是来匹配特殊的请求地址,例如,你想匹配一个文章地址,格式类似/blog/<year>/<month>/<post title slug>
workbox.routing.registerRoute(
new RegExp('/blog/\\d{4}/\\d{2}/.+'),
handler
);
和字符串匹配一样,正则匹配也会受到域名的限制,正则匹配如果想匹配跨域匹配,也需要从地址最开始进行匹配。
例如,上面的代码中的正则不会跨域匹配,如果想匹配其它域名地址的资源,需要进行全地址匹配,如下代码:
workbox.routing.registerRoute(
new RegExp('.+/blog/\\d{4}/\\d{2}/.+'),
handler
);
其它资源地址也是类似的写法,都需要添加一个 .+ 正则来进行全地址匹配
workbox.routing.registerRoute(
new RegExp('.+\\.js$'),
jsHandler
);
workbox.routing.registerRoute(
new RegExp('.+\\.css$'),
cssHandler
);
回调函数匹配
为了给予了开发人员更大的灵活性来匹配请求地址,Workbox提供了回调函数进行匹配,由你来写代码决定一个请求是否按照你的条件匹配。
这个函数将接收一个对象参数,包含了URL地址,和service worker的FetchEvent事件对象。
const matchFunction = ({url, event}) => {
// Return true if the route should match
return false;
};
workbox.routing.registerRoute(
matchFunction,
handler
);
现在,路由可以匹配请求,也是时候来处理这些请求了(也就是提供请求的响应)
有两种方式,你可以处理请求:
- 使用Workdbox提供的workbox.strategies方法来处理。
- 提供一个回调函数,返回包含Response响应的Promise对象。
使用Workbox的Strategy来处理路由
大部分路由都内置的缓存策略来处理的。
- Stale While Revalidate(重新验证过期)
- 当前策略会在缓存有效的情况下使用缓存响应,同时在后台使用网络更新缓存。(如果缓存无效的情况下,会等到网络请求响应再使用。)这是一种相对安全的策略,意味着用户会定期的更新缓存 。缺点就是,它总是请求网络,会占用用户的带宽。
- Network First(网络优先)
- 当前策略会优先从网络请求并响应,如果接到响应,将把它传给浏览器,同时进行缓存。如果网络请求失败,会使用最新的缓存资源进行响应。
- Cache First(缓存优先)
- This strategy will check the cache for a response first and use that if one is available. If the request isn’t in the cache, the network will be used and any valid response will be added to the cache before being passed to the browser.
- 当前策略会检查缓存资源是否有效,如果有效,会优先使用缓存进行响应。如果请求的资源不在缓存中,会再请求网络,并将有效的响应先加载到缓存中,再传给浏览器使用。
- Network Only(仅网络)
- 强制从网络请求资源。
- Cache Only(仅缓存)
- 强制从缓存请求资源。
代码如下:
workbox.routing.registerRoute(
match,
new workbox.strategies.StaleWhileRevalidate()
);
workbox.routing.registerRoute(
match,
new workbox.strategies.NetworkFirst()
);
workbox.routing.registerRoute(
match,
new workbox.strategies.CacheFirst()
);
workbox.routing.registerRoute(
match,
new workbox.strategies.NetworkOnly()
);
workbox.routing.registerRoute(
match,
new workbox.strategies.CacheOnly()
);
每一个策略,通过定义自定义缓存使用和 / 或者 添加插件,都可以自定义路由行为。
new workbox.strategies.StaleWhileRevalidate({
// Use a custom cache for this route.
cacheName: 'my-cache-name',
// Add an array of custom plugins (like workbox.expiration.Plugin).
plugins: [
...
]
});
在缓存请求时(例如,限制它们被缓存的时间或确保设备上使用的数据受到限制),通常需要使用这些选项来使其更安全。
使用自定义回调处理路由
在某些情况下,你可能希望使用自己不同的策略来响应请求,或是使用模板生成service worker的请求。为此,你可以提供异步函数返回一个Response对象。函数包含了url和event(FetchEvent对象)属性。
const handler = async ({url, event}) => {
return new Response(`Custom handler response.`);
};
workbox.routing.registerRoute(match, handler);
有一件事需要注意,如果你在回调函数匹配返回一个值,这个值将传递给处理请求函数作为 params 参数。
const match = ({url, event}) => {
return {
name: 'Workbox',
type: 'guide',
};
};
const handler = async ({url, event, params}) => {
// Response will be "A guide to Workbox"
return new Response(
`A ${params.type} to ${params.name}`
);
};
workbox.routing.registerRoute(match, handler);
如果URL中的某些信息可以在匹配的
回调中解析一次并在处理请求回调中使用,这个params参数会对你有所帮助。