FrankKai / FrankKai.github.io

FE blog

Home Page:https://frankkai.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

HTTP缓存之Cache-Control

FrankKai opened this issue · comments

  • 初识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-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