Service Workers
定义
Service Workers 主要是通过对本网站中所有的HTTP请求进行拦截,并对期进行缓存控制或者响应控制。
引入
Service Worker 其实就是后台线程中运行的javascript文件,所以引入的方式与其他js文件相同
eg:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23<html>
<head>The best web page ever</head>
<body>
<script>
// 注册 service worker
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("/sw.js")
.then(function(registration) {
// 注册成功
console.log(
"ServiceWorker registration successful with scope: ",
registration.scope
);
})
.catch(function(err) {
// 注册失败 :(
console.log("ServiceWorker registration failed: ", err);
});
}
</script>
</body>
</html>
即
- 检查当前浏览器是否支持 Service Workers
- 如果支持,注册一个叫做 ‘sw.js’ 的 Service Worker 文件
- 如果成功则打印到控制台
- 如果发生错误,捕获错误并打印到控制台
然后我们在注册的sw.js文件中添加一下内容1
2
3
4
5self.addEventListener('fetch', function(event) {
if (/\.jpg$/.test(event.request.url)) {
event.respondWith(fetch('/images/unicorn.jpg'));
}
});
- 为 fetch 事件添加事件监听器
- 检查传入的 HTTP 请求是否是 JPEG 类型的图片
- 尝试获取独角兽的图片并用它作为替代图片来响应请求
以上我们就成功的在浏览器中通过注册Service Workers的方式代理了本网站的所有请求。并选择我们需要控制的请求,返回特定的响应结果
> 需要注意的是,使用Service Worker 技术一定要https协议才可以,主要是怕被恶意注册非法Service Worker使网站全部请求被劫持。不过本地调试的时候访问localhost不受限制
控制缓存
预缓存
我们可以再 Service Workers 加载的时候,缓存你想要的资源。即用户首次访问本网站, Service Workers会下载并安装自己,我们可以再这个过程中将需要的内容(例如:常用的静态资源)加载好。
eg:1
2
3
4
5
6
7
8
9
10var cacheName = 'helloWorld';
self.addEventListener('install', event => {
event.waitUntil(
caches.open(cacheName)
.then(cache => cache.addAll([
'/js/script.js',
'/images/hello.png'
]))
);
});
- 首先为缓存创建一个名称cacheName(方便以后对缓存进行精准控制)
- 进入Service Workers的安装事件中
- 使用我们指定的缓存名称来打开缓存
- 把需要的js文件和图片文件添加到缓存中
需要注意的是:在缓存文件下载的过程中,任何文件下载失败都会导致安装过程的失败,使得Servicer Worker安装失败
监听缓存
让 Service Worker 开始监听 fetch 事件,如果遇到了匹配的的资源请求,则自动从缓存中获取内容
1 | self.addEventListener("fetch", function(event) { |
- 添加 fetch 事件的事件监听器
- 检查传入的请求 URL 是否匹配当前缓存中存在的任何内容
- 如果有 response 并且它不是 undefined 或 null 的话就将它返回
- 否则只是如往常一样继续,通过网络获取预期的资源
拦截请求同时缓存
一个请求被捕获的时候,首先检查请求的资源是否存在于缓存之中。如果存在,我们可以就此返回缓存并不再继续执行代码。
如果请求的资源于缓存之中没有的话,我们就重新发起网络请求。然后,我们需要检查 HTTP 响应,确保服务器返回的是成功响应并且没有任何问题。
如果成功响应,我们会再次克隆响应。你可能会疑惑我们为什么需要再次克隆响应
最后,将这个这个响应的结果添加至缓存中,以便下次再使用它。如果用户刷新页面或访问网站另一个请求了这些资源的页面,它会立即从缓存中获取资源。
eg:
1 | var cacheName = "helloWorld"; |
- 自定义缓存的名称
- 为 fetch 事件添加事件监听器以拦截请求
- 当前请求是否匹配缓存中存在的任何内容?
- 如果匹配的话,就此返回缓存并不再继续执行
- 这很重要,我们克隆了请求。请求是一个流,只能消耗一次。
- 尝试按预期一样发起原始的 HTTP 请求
- 如果由于任何原因请求失败或者服务器响应了错误代码,则立即返回错误信息
- 再一次,我们需要克隆响应,因为我们需要将其添加到缓存中,而且它还将用于最终返回响应
- 打开名称为 “helloWorld” 的缓存
- 将响应添加到缓存中
处理额外的查询参数
当 Service Worker 检查已缓存的响应时,它使用请求 URL 作为键。默认情况下,请求 URL 必须与用于存储已缓存响应的 URL 完全匹配,包括 URL 查询部分的任何字符串。
如果对文件发起的 HTTP 请求附带了任意查询字符串,并且查询字符串会更改,这可能会导致一些问题。例如,如果你对一个先前匹配的 URL 发起了请求,则可能会发现由于查询字符串略有不同而导致该 URL 找不到。当检查缓存时想要忽略查询字符串,使用 ignoreSearch 属性并设置为 true 。
eg:1
2
3
4
5
6
7
8
9self.addEventListener('fetch', function (event) {
event.respondWith(
caches.match(event.request, {
ignoreSearch: true
}).then(function (response) {
return response || fetch(event.request);
})
);
});
其他选项:
- ignoreMethod:忽略请求方法
- ignoreVary:忽略请求中的vary首部