3

一、证件照场景

拍一次证件照麻烦且费钱,因此每次拍的时候我们都会多留几张备用。这就是计算机世界的缓存,在现实世界中的写照。

如果某个行为很消耗资源,很麻烦,那在实现它的时候就顺便多保留几份,这种行为就是缓存。特点很明显

  • 容量有限,我们不可能留一屋子的备用照片

  • 有时效性,小时候的证件照长大了不能用吧

二、HTTP 缓存

缓存是一个比较笼统的概念,几乎任何行为都可以将结果缓存起来,尤其那些模块与模块的连接处,例如计算机世界的数据库查询,网络I/O等等,而人类世界诸如找人事部开收入证明、去婚姻登记处开未婚证明等等基本上会多开两三份。

本文讨论的是 HTTP 协议层面的缓存,它规范了浏览器和服务器在发送和接收到 HTTP 报文时,应该怎么解析和处理其中的缓存逻辑。其关键路径如下图所示

图 1 HTTP 缓存关键路径
clipboard.png

三、关键路径之验证缓存

浏览器发起一个请求,生成 HTTP 报文,先发送到缓存器,缓存器验证是否有本地缓存,缓存是否过期等,即图 1 的第一条路径,称之为验证缓存。

这个过程有三种结果:

  • 不存在缓存

  • 存在缓存,且缓存未过期(由 Cache-control 或 Epire 决定)

  • 存在缓存,但缓存已过期

如果存在缓存,且缓存未过期,则使用缓存响应客户请求,而不会向服务器发送请求。其它两种情况,都会将 HTTP 报文发送给服务器,那么服务器将怎么处理?

四、关键路径之服务器再验证

HTTP 报文经过缓存器进行验证后,除了使用本地缓存的情况,其他都会向服务器发请求,服务器处理逻辑如下

  • 本地不存在缓存情况,报文将直接被发送给服务器,服务器响应请求,并且在响应的报文中带上资源的缓存控制信息

  • 如果本地存在缓存,但缓存已过期,那么缓存器将在请求报文中带上 if-None-Match(取值对应ETag) 和 if-Modified-Since (取值对应 Last-Modified),服务器分别对这两个字段进行校验。有更新则返回新的资源文件、新缓存控制信息;没有更新则返回 304、以及新的缓存控制信息,浏览器更新缓存,并响应本地缓存文件。

服务器响应的缓存控制信息,包含Cache-Control 和 Expire,以及 ETag 和 Last-Modified,如图2

图2 服务器正常响应包含的缓存控制信息
clipboard.png

五、小结

完整的关键路径,存在以下可能

图3 缓存关键路径的几种情况
clipboard.png

  • 浏览器第一次访问某文件,本地无缓存,服务器响应文件资源,并包含 Cache-Control 和 Expire,浏览器缓存器据此缓存资源。报文还会包含 ETag 和 Last-Modified

  • 浏览器再次请求该文件,如果有缓存,由缓存信息中的 Cache-Control 和 Expire 决定缓存是否过期,没过期则直接使用缓存;过期则利用ETag 和 Last-Modified 询问服务器是否修改过该文件,服务器验证后,发现文件修改过则响应新的文件和缓存控制信息,缓存器更新缓存并响应新文件;若未修改过则返回304和缓存控制信息,缓存器更新缓存控制信息,并响应本地缓存文件给浏览器

六、问题

完整的关键链路已经说完!比较理想的情况下,有ETag、Last-Modified,有Cache-Control、Expire,但实现又不总是完美的,关于缓存还有以下问题需要弄清楚

  1. 服务器没有响应 Cache-Control、Expire 会出现什么情况?这种情况下,ETag 和 Last-Modified 还有用吗?

  2. ETag 和 Last-Modified 功能有些类似,它们的作用有何区分?Expire 和 Cache-Control max-age 存在同样的问题。

  3. ETag 是什么?Last-Modified 又是什么?

  4. 怎么设置这些头部信息?

  5. 浏览器点击刷新按钮,点击重新加载会出现什么情况?客户端向服务器发送Cache-Control 会出现什么情况
    Cache-Control 的取值有很多,各自的意义是什么?


啃先生
1.4k 声望1.2k 粉丝

前腾讯前端开发工程师,后来有一年时间经历参与创业,目前东南亚电商 Shopee,人在深圳。个人作品: