1. http缓存
http缓存分为两种:
- 强制缓存
- 协商缓存
缓存作为http优化的手段,主要是通过将相应内容存储到本地,以减少http请求的发生。
简单而言,客户端在第一次请求某个url时,将响应内容存储至本地,再下一次请求同样的url时,直接从本地获取响应内容。同时,这也带来一个问题,万一缓存的内容并不是最新的,客户端并不知情,这种情况如何处理,这也缓存策略发挥作用的地方。
1.1 强制缓存
强制缓存下,响应会指定此次响应内容的过期时间,而浏览器在下次请求时会判断缓存是否过期,未过期则直接使用缓存内容。
涉及两个HTTP响应头字段:
Cache-Control相对时间,优先级更高Expires是设置过期时间(绝对时间),但是如果用户的本地时间错乱了,可能会有问题
在有效期内请求会使用缓存,在有效期外会向服务器重新请求内容,并根据响应头内容更新对应字段。
1.2 协商缓存
协商缓存下,浏览器是否使用缓存内容,需要多一步与服务端协商的过程。
服务端协商通过后,会使用响应码304告诉浏览器可以使用本地资源(与服务端协商之后,通过协商结果来判断是否使用本地缓存。)
两种实现:
- 第一种 基于时间
- 响应头部使用
Last-Modified,标识该资源最后的修改时间 - 请求头部使用
If-Modified-Since,询问在此时间之后该资源是否有修改,服务端将该值与本地文件的修改时间做比较,- 如果相同,则相应304
- 否则200返回资源
- 问题:时间篡改
- 响应头部使用
- 第二种 基于标识
- 响应头部使用
ETag,表示该资源的唯一标识 - 请求头部使用
If-None-Match,通过对比浏览器和服务器资源的特征值(如MD5)来决定是否要发送文件内容,- 如果一样就只发送 304(not modified)
- 否则200返回资源
- 可准确判断文件内容是否被修改
- 响应头部使用
Etag的优先级比Last-Modified高:
- 没有修改内容,但修改了时间的情况
- 时间粒度问题:文件在1秒内多次修改
- 有些服务器不能精确获取文件的最后修改时间。
1.3 两种缓存关系
协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求
优先使用强制缓存,再使用协商缓存,而在协商缓存中,优先使用ETag,再使用Last-Modified。
完整流程如下:
1.4 Cache-Control相关字段
1.4.1 max-age
先了解一下前面讲的Expires用的是绝对事件,具体如下:
Expires: Wed, 21 Oct 2021 07:28:00 GMT
而Cache-Control中使用max-age表示存储的有效期,是个相对时间,单位为秒,如下所示用600表示6分钟
Cache-Control: max-age=600
1.4.2 public / private
响应传输过程中会经过大量代理服务器,可以使用public和private控制代理服务器的缓存行为
- public:公共缓存,任意方可缓存
- private:私有缓存,仅接收方缓存,代理服务器不可缓存
其中public情况下可为代理服务器的资源设置过期时间:
Cache-Control: s-maxage=604800
1.4.3 no-cache / no-store
Cache-Control: no-cache
no-cache用于防止从缓存中返回过期的资源
no-cache并不是表示不可缓存,而是每次使用资源时都要进行一次协商缓存,查询缓存是否有效
no-cache 相当于禁掉了强缓存,每次都要协商下
Cache-Control: no-store
no-store是真正地不允许缓存
1.4.4 must-revalidate
must-revalidate表示一旦资源过期,在成功向原始服务器验证之前,不能使用。
一般情况下,用户并不会使用过期的资源,但一些CDN厂商会使用过期资源,这个时候设置must-revalidate可以禁止这类情况的发生。
Cache-Control: max-age=0; must-revalidate;
分析以上指令,到期时间为0,即该资源立马过期,而设置了must-revalidate表示过期了的资源不可用,需要验证,所以必定会发起验证。
要使用必须先发起验证,其实以上等价于
Cache-Control: no-cache