http 缓存
根据请求是否达到服务端,可以将缓存分为 强缓存
和 协商缓存
强缓存
只在客户端即可判断是否命中的缓存
常用响应头有 Pragma
, Expires
请求头有 Cache-Control
(也可能存在于响应头中)
这些字段配置后不到期的请求不会到达服务端
Pragma
在 HTTP/1.0
协议中规定的通用首部,其效果依赖不同的实现,在请求到响应时可能会有不同的效果
现在只用来兼容只支持 HTTP/1.0
协议的缓存服务器
该头并没有一个明确的规范,所以可靠性不行,除非要兼容 HTTP/1.0
客户端,不然不建议使用
语法很简单且只有如下一种指令
1 | Pragma: no-cache |
与 Cache-Control: no-cache
效果一致,强制要求服务器验证缓存
Expires
该响应头存放着一个 HTTP标准时间戳
,用于设置资源的过期时间,格式如下
1 | Expires: <http-date> |
浏览器在请求一个资源的时候,会拿当前时间与该资源上次请求时的 Expires
对比,如果没有超过则读取本地缓存,否则向服务器请求资源
例如我们用拉起一个简单的 http 服务器:
1 | app.use(async (ctx, next) => { |
我们在三秒内请求该资源多次,观察浏览器调试器可以发现除首次请求外都使用了磁盘缓存
且服务端控制台只打印了一次 request
三秒后再次请求一次,会发现没有走缓存
该响应头返回的是绝对时间,因此客户端与服务端之间的时间差如果过大,会出现缓存失效、更新不及时的问题
下文的 Cache-Control
更加完善且优先级比 Expires
高
Cache-Control
该指令请求头和响应头中都可能存在,该指令是单向的,这意味着响应中不一定会有
语法规则如下:
不区分大小写,建议小写
多个指令逗号分隔
有可选参数,可以用令牌或者带引号的字符串语法
请求指令
客户端在请求时的指令
1 | Cache-Control: max-age=<seconds> // 必填参数例子(尖括号) |
响应指令
服务端在响应时的指令
1 | Cache-control: must-revalidate |
指令作用
这边只记录些常用的,其它的查文档不香吗
public
表示响应可以被任何对象缓存(客户端、代理服务器、等等),即使是一个通常来说不能被缓存的内容:
POST 请求
没有
max-age
或者Expires
no-cache
强制走协商缓存(先向服务器确认后才决定是否用本地缓存)
no-store
不使用任何缓存
max-age=<seconds>
缓存最大周期,设置一个相对时间,超过该相对时间的缓存被判定过期
only-if-cached
只接受已缓存的响应,并且不向服务器进行任何请求以检查更新
协商缓存
顾名思义,需要和服务器“协商”的缓存
常用响应头有 Last-Modified
, ETag
常用请求头有 If-Modified-Since
, If-None-Match
,一般与上面的响应头成对使用
协商缓存会向服务器询问资源是否需要更新,若无需则使用缓存,否则服务器返回新资源
Last-Modified
是一个响应头部,包含了该响应资源的最后修改时间,用于判断资源的一致性
语法:
1 | Last-Modified: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT |
具体格式看文档
If-Modified-Since
是一个请求头部,服务器只会在资源最后修改时间大于该值时返回最新的资源(资源在这之后修改了,需要更新),状态码 200
。
如果请求的资源在这之后都没有修改,那么会在响应头的 Last-Modified
中存放资源上次修改时间,并且返回一个不带主体的 304
响应,客户端收到响应后会使用本地缓存
客户端一般会在再次请求同一资源时将上次 Last-Modified
的值放在该次请求头部 If-Modified-Since
中
If-Modified-Since
只能用在 GET
,HEAD
请求中
该请求头一般用在响应中无 ETag
的资源上,是其备选方案
ETag
是响应头,记录了资源特定版本的标识符,用于判断资源是否变动
ETag
的生成方法没有指定,一般计算哈希值
语法:
1 | ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4" // 强验证 |
If-Math
是请求头,配合 ETag
使用
再次请求某资源时,带上上次响应的 ETag
并放在 If-Math
中发送
如果客户端发送的标识与服务端不匹配,则返回最新的资源和最新的 ETag
如果匹配则返回不带内容的 304
响应,客户端读取本地缓存
避免数据冲突
除了缓存外,还能解决一些冲突问题
具体可以看MDN 的例子
参考
Pragma | MDN
Expires | MDN
HTTP 日期/时间标准 | 简书
Cache-Control | MDN
Last-Modified | MDN
If-Modified-Since | MDN
ETag | MDN