参考原文:
彻底弄懂强缓存与协商缓存⭐⭐⭐⭐⭐
(一) 浏览器的缓存机制
- 浏览器与服务器通信的方式为应答模式,即是:浏览器发起HTTP请求 – 服务器响应该请求。
- 浏览器第一次向服务器发起该请求后拿到请求结果,会根据响应报文中 HTTP头的缓存标识,决定是否缓存结果, 是则将请求结果和缓存标识存入浏览器缓存中,
1. 第一次发起请求的简单过程如下图:
2. 浏览器缓存机制的关键
由上图我们可以知道:
- 浏览器每次发起请求,都会先在浏览器缓存中查找该请求的结果以及缓存标识
- 浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中
以上两点结论就是浏览器缓存机制的关键,他确保了每个请求的缓存存入与读取;
根据是否需要向服务器重新发起HTTP请求将缓存过程分为两个部分,分别是强制缓存和协商缓存,由后端服务器设置。
(二)强缓存(max-age)
1. 触发条件:
- 在客户端发起请求之前,先检查的
cache-control里的max-age有没有过期 - 如果没有过期直接使用该缓存,过期则走协商缓存
2. 触发过程
- 在客户端发起请求之前,先检查强缓存
- 查看强缓存的
cache-control里的max-age,判断数据有没有过期,如果没有直接使用该缓存
有些用户可能会在没有过期的时候就点了刷新按钮,这个时候浏览器就回去请求服务端
要想避免这样做,可以在cache-control里面加一个immutable
这样用户再怎么刷新,只要 max-age 没有过期就不会去请求资源
3. cache-control相关属性
| 标题 | 解释 cache-control: max-age=xxxx,public/private,... |
|---|---|
max-age=xxxx | 在xxx秒的有效期内,如果有请求该资源的需求的话就直接读取缓存, statu code:200 ,如果用户做了刷新操作,就向服务器发起http请求 |
public | 客户端和代理服务器都可以缓存该资源 |
private | 只让客户端可以缓存该资源;代理服务器不缓存 |
immutable | 在没有过期的时候,即使用户做了刷新操作,也不向服务器发起http请求 |
no-cache | 不允许强缓存,可以协商缓存 一般如果你做了强缓存,只有在强缓存失效了才走协商缓存的, 设置了no-cache就不会走强缓存了,每次请求都回询问服务端。 |
no-store | 不缓存,这个会让客户端、服务器都不缓存,也就没有所谓的强缓存、协商缓存了。 |
4. 强缓存步骤示例
cache-control: max-age=xxxx,immutable:
- 第一次请求 a.js ,缓存表中没该信息,直接请求后端服务器。
- 后端服务器返回了 a.js ,且 http response header 中
cache-control 为 max-age=xxxx,所以是强缓存规则,存入缓存表中。 - 第二次请求 a.js ,缓存表中是 max-age, 那么命中强缓存
- 然后判断是否过期,如果没过期,直接读缓存的a.js,如果过期了,则执行协商缓存的步骤
(三)协商缓存
1. 触发条件:
Cache-Control的值为no-cache(不强缓存)- 或者
max-age过期了 (强缓存,但总有过期的时候)
2. 触发过程
- 浏览器加载资源时,没有命中强缓存,这时候就去请求服务器;
- 请求服务器的时候,会带着两个参数(
If-None-Match、If-Modified-Since),服务器收到请求后,去检验缓存是否真的过期;两个参数 说明 If-None-Match表示是否命中,响应头中的 etag属性,每个文件对应一个etagIf-Modified-Since表示是否过期,响应头中的 Last-Modified属性 - 服务器会比较资源的最后修改时间(通过
If-Modified-Since头)或者资源的唯一标识符(通过If-None-Match头)与请求中的值;
如果没有过期,则服务器会给浏览器返回一个304状态码,表示缓存没有过期,可以使用旧缓存,过期则返回200; - 客户端接收到响应后,如果是304响应,它将使用先前缓存的资源;如果是200响应,它将更新缓存并使用新的资源。
3. etag的作用
- 有时候编辑了文件,但是没有修改,但是last-modified属性的时间就会改变,导致服务器会重新发送资源;
- 但是etag的出现就完美的避免了这个问题,他是文件的唯一标识
4. last-modified和etag各自的优缺点:
- 每个文件都有一个 etag 和 last-modified 属性,etag 要优先于 last-modified
- 两个属性各有优缺点,比如
last-modified很多时候不能感知文件是否改变,但 etag 能; - last-modified 仅仅记录了时间点,性能肯定要高于etag,etag 记录的是哈希值