为什么需要前端缓存
- 重复利用资源,提高网页打开资源
- 减少 http 请求,减少网络带宽
两种缓存
200(from cache)和 304(not modified)
- 强缓存:200(from cache)强缓存命中不会发送请求到服务端,直接从本地缓存中获取资源
- 协商缓存:会发送请求到服务器,服务器通过请求头部字段来验证资源是否命中协商缓存,如果命中,返回 304,通知浏览器从缓存中获取资源
与缓存策略相关的字段
三个字段 Cache-Control,Pragma,Expires(过期时间),下面介绍一下响应头中的
Cache-Control
http1.1 新增的字段,是控制浏览器缓存的主要字段。
- no-cache:资源可以被缓存,但是立刻过期,下次访问必须验证资源有效性
- max-age:缓存资源,在指定时间(是 res 里面的 Date 字段)后过期,单位是秒
- no-store:资源不会被缓存
- public:资源可以被浏览器和代理服务器缓存
- private:资源只能被浏览器缓存
Pragma
- 是 http1.0 的字段,只有一个值 no-cache,功能和 Cache-control:no-cache;一样,但是优先级比他低。
Expires
- 是缓存到期时间,是一个服务器的绝对时间,由于时区的误差等因素已经较少使用。优先级比 Cache-control:max-age 低。
强缓存命中条件
- 有些场景下必须避免浏览器缓存,响应头可以这样设置:Cache-Control: no-cache, no-store, must-revalidate(必须验证)
- 公开资源直接命中强缓存,这是响应最快的。
- 请求头部不包括 Pragma 字段
- 响应头部 Cache-Control 中不包括 no-cache、no-store
- 响应头部 max-age 或者 expire 大于请求日期
- 如果我们在很短的一段时间内多次访问同一个资源,并且响应头部却没有 max-age 或者 expires 信息,是不是就不会命中强缓存?不是的,浏览器会做出优化,默认会使用一个启发式算法,取响应头(Date-Last-Modified)*0.1 作为缓存的有效时间(其实就相当于 max-age),只要在这段时间内请求这个资源,即使没有缓存过期字段,也会命中强缓存
协商缓存命中条件
Last-Modified/If-Modified-Since
- 响应头会有一个 Last-Modified,代表这个资源最后修改的时间。
- 当浏览器再次向服务器请求该资源的时候,会传送 If-Modified-Since(也就是上次服务器传送过来的 Last-Modified),服务器会拿这个值跟本地资源实际最后修改时间作比较,如果文件没有被修改,那么返回 304,通知浏览器从缓存中读取文件。
ETag/If-None-Match
- ETag 是一个响应首部字段,他是根据资源内容生成的一段 hash 值,标识资源的状态,由服务器产生。
- 当浏览器再次向服务器端请求这个资源,会带上 If-None-Match(其实就是上次服务器发过来的 ETag 的 hash 值),服务器收到后,会拿这个值和资源实际的 ETag 做比较。
- 如果一样就命中协商缓存,返回 304
ETag 的优先级比 Last-Modified 高
- 本来已经有了一个 Last-Modified,为什么还需要 ETag?
- 这是因为 Last-Modified 只能精确到秒,而如果我们在服务器一秒内多次更改资源,那么将无法识别,还是会命中协商缓存
- 而且某些服务器不能精确得到文件的最后修改时间
- 一些文件或许会周期性被更改,但是他内容并没有改变,只是改变了修改时间,这个时候我们并不希望浏览器重新请求这个资源