FrankKai / FrankKai.github.io

FE blog
https://frankkai.github.io/
362 stars 39 forks source link

HTTP缓存之Cache-Control #240

Open FrankKai opened 3 years ago

FrankKai commented 3 years ago

初识Cache-Control

Cache-Control HTTP头可用于为request和response保存指令(directive或instruction)。 request中一个给定的directive并不是意味着这个directive在response也需要出现。

属性
头类型 普通头
禁用头名字
CORS安全型response头

先来看看Cache-Control都有哪些值。

语法篇

缓存指令需要遵守以下的规则才是有效的:

扩展(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的值各自代表什么意思。

指令篇

缓存性

初识缓存性

如果一个response满足以下条件,浏览器会将其缓存起来:

public(任意缓存)

response可以被存储在任何的缓存中,即使这response是不能缓存的。

private(浏览器缓存)

response只能存储在浏览器的缓存中,即使response是不能缓存的。 private指令不能阻止缓存响应。如果你不想将response存储在任何cache,需要使用no-store。

no-cache(很常见)

Cache-Control: no-cache恐怕是最最常见的值了。

有效期

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-MatchIf-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后请求有什么变化?

image

http请求的cache-control header会变为:no-cache。

// request header
cache-control: no-cache

七牛云资源

image

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