HTTP协议之缓存策略

90 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

为什么要有缓存?

HTTP请求本身比较耗时,对于一些很少变化的资源,可以通过缓存减少网络请求,让页面加载更快。

通常会缓存静态资源(css,js,img),对于动态计算的页面则不会缓存。

强制缓存和协商缓存

缓存分为强制缓存和协商缓存,由服务器和浏览器共同控制。

  1. 强制缓存就是无条件缓存,优先级最高,浏览器在资源有效时间内不会请求服务器,直接使用。
  2. 协商缓存就是浏览器在使用前要访问服务器,问一问资源能不能用,服务器说能用才会用。

服务器缓存控制

强制缓存

强制缓存中,服务器只需要在响应头部中返回Cache-Control字段即可控制。该字段指定了资源过期时间,资源只要不过期,浏览器就会一直使用。

Cache-Control常用取值:

  • max-age:最大过期时间,单位。如果max-age=0,则同no-cache
  • no-cache:无强制缓存,有协商缓存
  • no-store:无强制缓存,也无协商缓存
  • private:只允许最终用户缓存,比如浏览器
  • public:允许代理服务器进行缓存

响应头部中Expires字段也用于控制缓存,优先级低于Catch-Control,属于比较老的标准。

max-age 是“生存时间”(又叫“新鲜度”“缓存寿命”,类似 TTL,Time-To-Live),时间的计算起点是响应报文的创建时刻(即 Date 字段,也就是离开服务器的时刻),而不是客户端收到报文的时刻,也就是说包含了在链路传输过程中所有节点所停留的时间。

协商缓存

协商缓存中,服务器需要在响应头部中返回Last-ModifiedETag记录资源状态,浏览器需要在请求头部中添加Last-Modified-SinceIf-None-Match携带资源状态去服务器进行校验,服务器比对发现资源一样则返回304,浏览器使用缓存,不一样则返回200和最新的资源。

资源状态记录字段:

  • Last-Modified:资源最后修改时间
    • 浏览器通过If-Modified-Since携带Last-Modified的值
  • ETag:资源唯一标识(一个字符串)
    • 浏览器通过If-None-Match携带ETag的值

ETag优先级高于Last-Modified,如果两者共存优先使用ETag。

  1. Last-Modified只能精确到秒级,ETag更精准一些。
  2. 如果资源被重复生成,而内容不变,则ETag更精准。

浏览器缓存控制

  • 前进后退:强制缓存和协商缓存均遵循服务器缓存策略
    • 如果有强制缓存,则不产生请求,直接返回(disk cache)
    • 如果有协商缓存,则携带If-Modified-Since或If-None-Match
  • ajax访问:强制缓存和协商缓存均遵循服务器缓存策略
    • 如果有强制缓存,则不产生请求,直接返回(disk cache)
    • 如果有协商缓存,则携带If-Modified-Since或If-None-Match
  • 页面刷新:输入URL回车或者点击刷新按钮,强制缓存失效,协商缓存遵循服务器缓存策略
    • 浏览器在请求头部中携带Cache-Control:max-age=0
    • 如果有协商缓存,则携带If-Modified-Since或If-None-Match
  • 强制刷新:shift+cmd+R,强制缓存和协商缓存均失效
    • 浏览器在请求头部中携带Cache-Control:no-cache
    • 浏览器不会携带If-Modified-Since或If-None-Match

缓存访问整体流程

  • 强制缓存是否有效?
    • 强制缓存有效则访问缓存,流程结束
    • 强制缓存失效则看是否有协商缓存?
      • 不存在协商缓存,访问服务器获取新数据,流程结束
      • 存在协商缓存,携带资源标识访问服务器
        • 服务器判定资源一致,返回304,使用缓存,流程结束
        • 服务器判定资源不一致,返回200和新数据,流程结束

如果强制缓存和协商缓存均失效,浏览器将删除该缓存