HTTP响应头的实现
如果一个网站中的某个文件是百年不变的,那么肯定没有必要打开网页都重新获取啊。我们可以设置HTTP返回头的Cache-Control。
-
max-age=31536000:过期时间(单位是秒),最大不能超过一年,只要没过期或者手动清除缓存就会使用缓存。
-
no-cache:每次使用缓存之前,向服务器对资源进行验证。最终实现不使用缓存的过期资源的效果。(不要理解为字面意思:不缓存)
-
no-store:不使用缓存
-
must-revalidate:如果设置了
max-age
,在有效期内会使用缓存,否则就需要进行验证。所以可以结合使用Cache-Control: must-revalidate, max-age=60
。
那么服务端怎么进行验证呢?服务器第一次返回的响应头中有一个ETag
字段,该字段相当于一个标识,具体的生成逻辑由服务端决定。
然后客户端之后的请求头中会携带一个If-None-Match
字段,这个字段就是那个标识。服务器通过对比这个标识判断资源是否发生了更新。
Expires VS max-age
在响应头中有时还有一个expires
字段,它和设置max-age
一样都是设置有效期的。不过expires
字段直接指定过期时间。而后者则是指定多长时间之后过期。
expires: Mon, 24 Dec 2018 13:55:24 GMT
last-modified VS Etag
在响应头中还有一个字段last-modified
,它也可以用来做验证。那么它与Etag
有什么区别呢?可以说Etag
应该是更为精准的,last-modified
最多精确到秒,而Etag
则是只要发生变化,标识就会改变。
last-modified: Thu, 01 Jan 1970 00:00:00 GMT
Service Workers
1、Service Workers是什么?
Service Workers
是浏览器在后台独立于网页运行的脚本,它可以支持离线体验。有以下几点注意事项:
-
它是一种JavaScript 工作线程,不能直接访问DOM
-
服务工作线程是一种可编程网络代理,让您能够控制页面所发送网络请求的处理方式。
-
它在不用时会被中止,并在下次有需要时重启
-
在开发过程中,可以通过 localhost 使用服务工作线程,但如果要在网站上部署服务工作线程,需要在服务器上设置 HTTPS。
2、生命周期
-
首先需要在我们的网页中注册
Service Workers
。注册会让浏览器后台执行Service Workers的安装步骤。 -
在Service Workers的独立脚本中,设置在安装过程中要缓存的文件,如果所有文件都缓存成功则安装成功;如果有任何一个失败都将失败,Service Workers就安装失败。
-
安装完成就该激活了,在这里我们对旧缓存进行管理。
-
激活之后,服务工作线程将会对其作用域内的所有页面实施控制
接下来,我们详细了解一下各个步骤的代码写法:
3、代码实现
在页面中注册Service Workers
,来启动安装。在register方法中告诉浏览器Service Workers
脚本的路径,这里是在根目录下,所以Service Workers
接受该域下所有的fetch事件。
// 判断浏览器对Service Workers的支持情况
if ('serviceWprker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/sw.js')
.then(registration => {
if (registration.waiting) {
console.log('安装完毕');
}
})
.catch(err => {
console.log(err);
});
});
}
接下来看一下Service Workers
中的安装过程,这里会监听一个install事件,在事件回调中又可以分为三部:
var CACHE_NAME = 'my-cache';
var cacheList = ['/', '/src/main.js'];
self.addEventListener('install', event => {
event.waitUntil(
caches.open(CACHE_NAME).then(cache => {
return cache.addAll(cacheList);
})
);
});
-
打开缓存,这里需要传入一个想要缓存的自定义名称。
-
缓存文件,可以是一个由想要缓存的文件路径组成的数组
-
确认所有需要的资产是否缓存,event.waitUntil() 方法带有 promise 参数并使用它来判断安装所花费的时间以及安装是否成功。
在安装完成之后,我们可能会想要一个对fetch事件的处理,当监听到fetch请求时,先匹配缓存中的内容,如果有就返回缓存的内容,没有则发起网络请求。
self.addEventListener('fetch', event => {
event.respondWith(
caches
.match(event.request)
.then(response => response || fetch(event.request))
);
});
这里如果想要连续缓存新的请求,可以处理fetch请求的响应并将其添加到缓存中。
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
if (response) {
return response;
}
// 如果时新的请求就克隆一个请求
var fetchRequest = event.request.clone();
return fetch(fetchRequest).then(res => {
// 校验响应,对第三方资产(type)的请求不会添加到缓存
if (!res || res.status !== 200 || res.type !== 'basic') {
return res;
}
// 该响应是Stream,所以主体只能用一次,需要克隆响应,一个发送给浏览器,一个保留在缓存中
var responseToCache = res.clone();
caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, responseToCache);
});
return res;
});
})
);
});
接着看,当某个时候,Service Workers
需要更新了,应该有以下步骤:
-
在用户打开页面的时候浏览器会尝试在后台重新下载定义了
Service Workers
的脚本。如果有变化了就认为是更新了。 -
这时新的
Service Workers
就会启动将触发install
事件,此时此刻旧的Service Workers
还在控制着页面,新的Service Workers
处于waitting状态 -
当前这个页面关闭之后,新的
Service Workers
就会占据控制权。 -
新服务工作线程取得控制权后,就会触发其 activate 事件。
在 activate 回调中一般就是进行缓存管理,把旧的Service Workers
清除掉。先定义一个新的缓存百名单,然后遍历Service Workers
所有的缓存,把不在白名单内的删除。
self.addEventListener('activate', event => {
// 白名单
var cacheWhiteList = ['new-cache'];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (cacheWhiteList.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});
网友评论