介绍

浏览器缓存可以提高网页打开速度、减少Http请求,在提高用户体验、重复利用资源、减少网络带宽上发挥着重要的作用。特别是现在用户对网站响应速度要求特别高的情况下,高效地利用浏览器缓存机制可以使网站性能优化事半功倍。
下面对浏览器缓存机制做一些分析。

概念

HTTP缓存可以分为强缓存协商缓存

  1. 强缓存:缓存命令不会发送请求到服务器,直接从本地缓存中获取资源,状态码200(form cache)
  2. 协商缓存:协商缓存会向服务器发送请求,服务器直接通过头部字段来验证资源是否命中协商缓存,如果命中,则返回状态码304(not modified),通知浏览器缓存中获取资源 。

示意图

分析

根据响应头部的字段确定浏览器缓存策略

响应头中与缓存策略相关的字段包括Cache-Control,Pragma,Expires,下面分析这三个字段:

# Cache-Constrol

Cache-Constrol是Http/1.1新增的字段、是控制浏览器缓存的主要字段。它的主要内容如下:

  1. no-cache:资源可以被缓存、但立即过期、下次访问必须验证资源有效性
  2. max-age:缓存资源、在指定时间后过期(单位:秒)
  3. no-store:资源不会被缓存
  4. public:资源可以被浏览器和代理服务器缓存
  5. private:资源只能被浏览器缓存

# Pargma

Pargma是Http/1.0的头部字段、只有一个值no-cache、功能和Cache-Constrol:no-Cache一样

# Expires

Expires是缓存到期时间、以服务器时间为参考、优先级比Cache-Constrol:max-age低。在一些场景中必须避免浏览器缓存、推荐的做法是设置请求头:
Cache-Constrol:no-cache,no-store,must-revalidata

强缓存命中条件

我们会发现、最优的做法是让一些公开资源命中强缓存,这是响应最快的。那么命中强缓存的条件又是什么呢?
1. 请求头部不包括Pragma字段
2. 响应头部Cache-Constrol不包括no-cacheno-store
3. 响应头部max-ageExpires大于请求日期

如果我们在很短的一段时间内多次访问同一个资源,并且响应头部却没有 max-age 或者 Expires 信息,是不是就不会命中强缓存了呢?不是的,浏览器会做出优化,默认采用一个启发式算法,取响应头的 (Date - Last-Modified) * 0.1作为缓存有效时间,只要是在这段时间内请求这个资源,即使没有缓存过期字段,也会命中强缓存。

服务端校验资源是否修改机制

# Last-Modified/If-Modified-Since

服务器响应资源的时候返回一个头部字段 Last-Modified,代表该资源最后修改时间,当浏览器再次向服务器请求该资源时,会传送 If-Modified-Since 信息,值就是上次服务器响应的最后修改时间, 服务器将这个请求时间与本地资源实际最后修改时间做对比,如果文件没有被修改,则返回状态码 304,通知浏览器从缓存中读取资源文件。

# Etag/If-None-Match

ETag 是一个响应首部字段,它是根据资源内容生成的一段hash字符串,标识资源的状态,由服务端产生。当浏览器再次向服务器请求该资源时,会传送If-None-Match 字段,服务器收到请求后,拿 If-None-Match字段的值与资源的实际 ETage 值进行比较,若相同,则命中协商缓存,返回状态码 304。ETag优先级比Last-Modified 高,同时存在时会以ETag 为准。

那已经有了 Last-Modified机制,为什么要引入 ETage 机制呢?
1. 服务器不能精确的得到资源的修改时间、这样就无法通过最后修改时间判断资源是否更新
2. 如果资源修改非常频繁、在秒以下的时间进行修改、而Last-Modified只能精确到秒
3. 一些资源的最后修改时间改变了、但是内容没有变化、使用Etag就能判别出资源内容是否被修改

浏览器缓存的使用

使用缓存的过程其实就是根据场景设置Cache-Constrol的值的过程: