浏览器缓存
# 浏览器缓存
# 按失效策略分类:强制缓存/强缓存
含义:当客户端请求后,会先访问缓存数据库看缓存是否存在。如果存在则直接返回;不存在则请求真的服务器,响应后再写入缓存数据库。
强制缓存直接减少请求数,是提升最大的缓存策略。 造成强缓存的字段是 Cache-control 和 Expires
Expires 这个字段表示缓存的时间,是一个绝对的时间(当前时间+缓存时间),如:
expires: Mon, 01 Mar 2021 10:25:05 GMT
1在响应头中设置该字段,意思即为告诉浏览器,在未过期之前不需要在修改。 缺点:
- 是绝对时间,用户可以修改本地客户端时间,导致浏览器判断缓存失效,重新请求资源。时差或误差等因素也可能造成客户端与服务端的时间不一致,致使缓存失效。
- 写法复杂, 表示时间的字符串多个空格,少个字母,非法属性都会导致设置失效。
Cache-control 该字段表示资源缓存的最大有效时间(相对时间),在该时间内,客户端不需要向服务器发送请求。如:
Cache-control: max-age=2592000
1常用的值:
- max-ages:即最大的有效时间,
- must-revalidate:如果超过了 max-age 的时间,浏览器必须向服务器发送请求,验证资源是否有效
- no-cache:字面意思是“不要缓存”,但实际上还是要求客户端缓存内容的,只是是否使用这个内容由后续的对比来决定
- no-store:真正意义上的“不要缓存”,所有内容都不走缓存,包括强制和对比
- public: 所有的内容都可以被缓存(包括客户端和代理服务器,如 CDN)
- private:所有的内容只有客户端才可以缓存,代理服务器不能缓存。默认值
这些值可以混合使用,混合使用时注意优先级: no-store —— no-cache —— public/private —— max-age 注意:
- max-age=0, must-revalidate 和 no-cache 等价
- Cache-control 的优先级比 Expires 高
# 协商缓存/对比缓存
当强制缓存失效时,就需要使用对比缓存,由服务器决定缓存内容是否失效。 浏览器先请求缓存数据库,返回一个缓存标识,之后浏览器拿这个标识和服务器通讯。如果缓存没有失效,则返回 HTTP 状态码表示继续使用,于是客户端继续使用缓存;如果失效,则返回新的数据和缓存规则,浏览器响应数据后,再把规则写入到缓存数据库。
协商缓存和没有缓存在请求数上是一致的(请求 —— 处理 - 响应),HTTP 返回 304 是优化的响应,通过减少响应体体积,来缩短网络传输时间。有以下两组字段
Last-Modified & If-Modified-Since 通过该字段告知客户端,资源最后一次被修改的时间。如:
Last-Modified: Mon, 10 Nov 2018 09:10:11 GMT
1浏览器将这个值和内容一起记录在缓存数据库中;下次请求资源时,浏览器从自己的缓存中找出“不确定是否过期的”缓存,在请求头中将上次的 Last-Modified 的值写入到请求头的 If-Modified-Since 字段;服务器会把If-Modified-Since和Last-Modified的值进行对比,如果一样,则表明未修改,响应 304,反之,表示修改了,响应 200 状态码,并返回数据。 缺点:
- 如果资源更新的速度是秒以下单位,该缓存不能使用,因为它的单位时间最低是秒
- 如果文件是服务器是动态生成的,该方法的最后修改时间永远是生成的时间,尽管文件可能没有变化,所以起不到缓存的作用。
Etag & If-None-Match Etag 存储的是文件的特殊标识,服务器存储这文件的 Etag 字段; 下次请求资源时,浏览器在请求头中将 Etag 的值写入到请求头中的 If-None-Match; 服务器会比较 Etag 与 If-None-Match 的值,如果一样返回 304, 如果不一样返回 200 和新资源。
Etag 的优先级高于 Last-Modified
# 浏览器请求资源过程
调用 Service Worker 的 fetch 事件响应
查看 memory cache
查看 disk cache,细分: (1)如果有强缓存且未失效,则使用强制缓存,不请求服务器,状态码全是 200 (2) 如果强制缓存失效,使用协商缓存,比较后确定返回 304 还是 200
发送网络请求,等待网络响应
把响应内容存入 disk cache(如果 HTTP 头信息配置可以存的话)
把响应内容的引用存入 memory cache(无视 HTTP 头信息的配置)
把响应内容存入 Service Worker 的 Cache Storage(如果 Service Worker 的脚本调用了 cache.put())