一、证件照场景
拍一次证件照麻烦且费钱,因此每次拍的时候我们都会多留几张备用。这就是计算机世界的缓存,在现实世界中的写照。
如果某个行为很消耗资源,很麻烦,那在实现它的时候就顺便多保留几份,这种行为就是缓存。特点很明显
容量有限,我们不可能留一屋子的备用照片
有时效性,小时候的证件照长大了不能用吧
二、HTTP 缓存
缓存是一个比较笼统的概念,几乎任何行为都可以将结果缓存起来,尤其那些模块与模块的连接处,例如计算机世界的数据库查询,网络I/O等等,而人类世界诸如找人事部开收入证明、去婚姻登记处开未婚证明等等基本上会多开两三份。
本文讨论的是 HTTP 协议层面的缓存,它规范了浏览器和服务器在发送和接收到 HTTP 报文时,应该怎么解析和处理其中的缓存逻辑。其关键路径如下图所示
图 1 HTTP 缓存关键路径
三、关键路径之验证缓存
浏览器发起一个请求,生成 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 服务器正常响应包含的缓存控制信息
五、小结
完整的关键路径,存在以下可能
图3 缓存关键路径的几种情况
浏览器第一次访问某文件,本地无缓存,服务器响应文件资源,并包含 Cache-Control 和 Expire,浏览器缓存器据此缓存资源。报文还会包含 ETag 和 Last-Modified
浏览器再次请求该文件,如果有缓存,由缓存信息中的 Cache-Control 和 Expire 决定缓存是否过期,没过期则直接使用缓存;过期则利用ETag 和 Last-Modified 询问服务器是否修改过该文件,服务器验证后,发现文件修改过则响应新的文件和缓存控制信息,缓存器更新缓存并响应新文件;若未修改过则返回304和缓存控制信息,缓存器更新缓存控制信息,并响应本地缓存文件给浏览器
六、问题
完整的关键链路已经说完!比较理想的情况下,有ETag、Last-Modified,有Cache-Control、Expire,但实现又不总是完美的,关于缓存还有以下问题需要弄清楚
服务器没有响应 Cache-Control、Expire 会出现什么情况?这种情况下,ETag 和 Last-Modified 还有用吗?
ETag 和 Last-Modified 功能有些类似,它们的作用有何区分?Expire 和 Cache-Control max-age 存在同样的问题。
ETag 是什么?Last-Modified 又是什么?
怎么设置这些头部信息?
浏览器点击刷新按钮,点击重新加载会出现什么情况?客户端向服务器发送Cache-Control 会出现什么情况
Cache-Control 的取值有很多,各自的意义是什么?
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。