FrankKai.github.io
FrankKai.github.io copied to clipboard
HTTP缓存之Cache-Control
- 初识Cache-Control
- 语法篇
- 缓存请求(request)指令
- 缓存响应(response)指令
- 扩展(Extension)指令
- req和res通用的指令
- 指令篇
- 缓存性
- 初识缓存性
- public
- private
- no-cache
- no-store
- 有效期
- max-age
- s-maxage
- max-stale
- min-fresh
- stale-while-revalidate
- stale-if-error
- 重验证和重加载
- must-revalidate
- proxy-revalidate
- immutable
- 其他
- no-transform
- only-if-cached
- 缓存性
- 最佳实践篇
- 阻止缓存
- 缓存静态资源
- 请求重新验证
- 实战分析篇
- 浏览器开启disable cache后请求有什么变化?
- 七牛云资源
- taobao.com的xxx.html
初识Cache-Control
Cache-Control HTTP头可用于为request和response保存指令(directive或instruction)。 request中一个给定的directive并不是意味着这个directive在response也需要出现。
属性 | 值 |
---|---|
头类型 | 普通头 |
禁用头名字 | 否 |
CORS安全型response头 | 是 |
先来看看Cache-Control都有哪些值。
语法篇
缓存指令需要遵守以下的规则才是有效的:
- 大小写敏感的,但是更加推荐小写
- 可以写多个directive,需要用逗号分隔
- 一些指令的directive是有可选参数的,可以是token或者带引号的字符串
缓存请求(request)指令
标准的Cache-Control可以通过client的HTTP请求发出。
Cache-Control: max-age=<seconds>
Cache-Control: max-stale[=<seconds>]
Cache-Control: min-fresh=<seconds>
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: only-if-cached
缓存响应(response)指令
标准的Cache-Control指令可用于HTTP response服务器。
Cache-Control: must-revalidate
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: no-transform
Cache-Control: public
Cache-Control: private
Cache-Control: proxy-revalidate
Cache-Control: max-age=<seconds>
Cache-Control: s-maxage=<seconds>
扩展(Extension)指令
扩展的Cache-Control指令不是核心HTTP缓存标准的一部分。需要检查兼容性列表。
Cache-Control: immutable
Cache-Control: stale-while-revalidate=<seconds>
Cache-Control: statle-if-error=<seconds>
req和res通用的指令
request和response都可用的directive有:
- Cache-Control:
max-age=<seconds>
- Cache-Control: no-cache
- Cache-Control: no-store
- Cache-Control: no-transform
再来看看Cache-Control的值各自代表什么意思。
指令篇
缓存性
初识缓存性
如果一个response满足以下条件,浏览器会将其缓存起来:
- 状态码为301,302,307,308或410 and
- Cache-Control头值不为no-store,没有private头 and
- Authorization头未设置
- 要么
- 状态码为301,302,307,308或410 or
- Cache-Control的值为public,max-age或s-maxage or
- Expires设置
public(任意缓存)
response可以被存储在任何的缓存中,即使这response是不能缓存的。
private(浏览器缓存)
response只能存储在浏览器的缓存中,即使response是不能缓存的。 private指令不能阻止缓存响应。如果你不想将response存储在任何cache,需要使用no-store。
no-cache(很常见)
Cache-Control: no-cache恐怕是最最常见的值了。
- 如果设置为no-cache,浏览器在每次使用资源前都需要做一次revalidate。
- response可以存储在任何缓存,即使response本身是不能缓存的。
- 存储的响应在使用之前必须向源服务器发出验证请求,所以不能将no-cache与immutable一起使用。
- 这个指令不能阻止缓存响应。如果你不想将response存储在缓存中,需要使用no-store。
no-store(真正的禁止缓存响应,需要重点关注)
- response不能在任何缓存中存储。
- 即使其他值设置了,在现代浏览器中这是唯一的阻止浏览器缓存response的指令。
- 隐式的max-age=0。
- must-revalidate不生效。这是因为如果想要做一次重验证的话,需要将response存储在cache中,而no-store不允许缓存response。
有效期
max-age=<seconds>
(新鲜的缓存)
资源保持fresh的最大时间。 与Expires不同,这个指令与请求的时间相关。
s-maxage=<seconds>
(新鲜的共享缓存)
覆盖max-age或者Expires头,仅仅作用于共享缓存(例如proxies)。 private缓存会忽略这个值。
max-stale[=<seconds>]
(不新鲜的缓存)
stale(旧的,不新鲜的)。 代表的是client将接收一个旧响应。 可选的值代表的是客户端接受的不新鲜时间上限。
min-fresh=<seconds>
(最小的新鲜缓存)
代表的是客户端会设置这个资源的最小缓存时间。
实验性的有效期directive:stale-while-revalidate=<seconds>
,stale-if-error=<seconds>
。
重验证和重加载
must-revalidate(缓存失效再次使用需要重新验证)
一旦资源变为stale(过期的),如果源server不能成功验证过期的副本,缓存是不能使用的。 也就是说如果缓存过期了,需要重新验证成功才能再继续使用。
proxy-revalidate
与must-revalidate类似,但是仅仅在共享缓存生效。会被private缓存忽略。
immutable(响应体万年不变。)
response的body不会随着时间的变化而变化。
如果资源未过期,也就是说在server上没有改变,所以client不会发出一个传统意义的revalidation。
例如If-None-Match
或If-Modified-Since
去检查更新,即使用户显式的刷新页面,immutable都不会重验证。
不知道这个扩展的客户端需要根据HTTP规范忽略它。在firefox中,immutable仅仅在https://协议中生效。
其他
no-transform(不允许对资源做转换)
不能有transformation或conversion在资源上发生。 Content-Encoding,Content-Range,Content-Type头不能通过proxy修改。 no-transform不允许对资源进行转换。例如有些代理或浏览器特性会转换图片的格式,从而节省缓存空间或者加速慢网的网络。
only-if-cached(仅仅使用缓存中的资源,不使用网络资源)
客户端设置的,将“不要使用网络”作为response。
缓存应该使用存储的响应进行响应,或者是504。
传统的例如If-None-Match这样的头,不应该被设置。如果服务器设置了only-if-cached
,没有影响。
最佳实践篇
阻止缓存
可以按照下面的方式关闭缓存:在response header中添加以下信息。
// Good
Cache-Control: no-store
// Bad
Cache-Control: private,no-cache,no-store,max-age=0,must-revalidate,pre-check=0,post-check=0
缓存静态资源
应用中的文件是不太会变化的,我们可以在response header中增加一个主动缓存。 比如对于服务器提供出的images,CSS文件和js文件。
Cache-Control: public, max-age=604800, immutable
请求重新验证
设置为no-cache或者max-age=0的话,客户端在每次使用资源前都需要发起一次重新验证。(重点重点重点) 这也就意味着每次发出HTTP请求前,如果内容是有效的话,可以跳过下载HTTP body。
Cache-Control: no-cache
Cache-Control: no-cache, max-age=0
Cache-Control: no-cache, max-age=0, stale-while-revalidate=300
实战分析篇
浏览器开启disable cache后请求有什么变化?
http请求的cache-control header会变为:no-cache。
// request header
cache-control: no-cache
七牛云资源
index.html、js文件,css文件
// response header
cache-control: public, max-age=86400(24小时)
// request header
cache-control: max-age=0
分析: req的cache-control:max-age=0/no-cache 浏览器不从缓存中获取资源,直接从远程server获取资源。client->server,浏览器获取最新资源。 res的cache-control:max-age=0/no-cache 浏览器不将此资源存储到缓存中。server->client,返回最新资源但是不缓存。
taobao.com的xxx.html
// response headers
cache-control: max-age= 2592000(30天), s-maxage=3600(1小时)
分析: 资源的最大缓存时间为30天,共享缓存仅仅是1小时。
参考资料: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control