Cache-Control
Cache-Control
HTTP 头字段包含用于控制浏览器和共享缓存(例如代理、CDN)中缓存的指令(说明)——在请求和响应中。
头类型 | 请求头,响应头 |
---|---|
禁止的头名称 | 否 |
CORS 安全列表响应头 | 是 |
语法
缓存指令遵循以下规则
- 缓存指令不区分大小写。但是,建议使用小写,因为某些实现不识别大写指令。
- 允许多个指令,并且必须用逗号分隔(例如,
Cache-control: max-age=180, public
)。 - 某些指令具有可选参数。提供参数时,它与指令名称之间用等号 (
=
) 分隔。通常,指令的参数是整数,因此不包含在引号字符中(例如,Cache-control: max-age=12
)。
缓存指令
下表列出了标准的 Cache-Control
指令
请求 | 响应 |
---|---|
max-age |
max-age |
max-stale |
- |
min-fresh |
- |
- | s-maxage |
no-cache |
no-cache |
no-store |
no-store |
no-transform |
no-transform |
only-if-cached |
- |
- | must-revalidate |
- | proxy-revalidate |
- | must-understand |
- | private |
- | public |
- | immutable |
- | stale-while-revalidate |
stale-if-error |
stale-if-error |
注意:请查看兼容性表格以了解其支持情况;不支持它们的 User Agent 应忽略它们。
词汇
本节定义了本文档中使用的术语,其中一些术语来自规范。
- (HTTP) 缓存
-
保存请求和响应以供后续请求重用的实现。它可以是共享缓存或私有缓存。
-
存在于源服务器和客户端之间(例如代理、CDN)的缓存。它存储单个响应并将其重用于多个用户——因此开发人员应避免将个性化内容存储在共享缓存中。
- 私有缓存
-
存在于客户端中的缓存。它也称为本地缓存或浏览器缓存。它可以存储和重用单个用户的个性化内容。
- 存储响应
-
当响应可缓存时,将其存储在缓存中。但是,缓存的响应并不总是按原样重用。(通常,“缓存”表示存储响应。)
- 重用响应
-
重用缓存的响应以供后续请求使用。
- 重新验证响应
-
询问源服务器存储的响应是否仍然新鲜。通常,重新验证是通过条件请求完成的。
- 新鲜响应
-
表示响应新鲜。这通常意味着响应可以重用于后续请求,具体取决于请求指令。
- 陈旧响应
-
表示响应为陈旧响应。这通常意味着响应不能按原样重用。缓存存储不需要立即删除陈旧响应,因为重新验证可以将响应从陈旧更改为新鲜。
- Age
-
自生成响应以来的时间。它是响应是否新鲜或陈旧的标准。
指令
本节列出了影响缓存的指令——响应指令和请求指令。
响应指令
max-age
max-age=N
响应指令指示响应保持新鲜,直到生成响应后N秒。
Cache-Control: max-age=604800
指示缓存可以存储此响应并在其新鲜期间将其重用于后续请求。
请注意,max-age
不是自接收响应以来的经过时间;它是自源服务器上生成响应以来的经过时间。因此,如果网络路由中其他缓存存储响应 100 秒(使用 Age
响应头字段指示),则浏览器缓存会从其新鲜生命周期中减去 100 秒。
如果 max-age
值为负数(例如,-1
)或不是整数(例如,3599.99
),则缓存行为未指定。鼓励缓存将该值视为 0
(这在 HTTP 规范的计算新鲜生命周期部分中有所说明)。
Cache-Control: max-age=604800
Age: 100
s-maxage
s-maxage
响应指令指示响应在共享缓存中保持新鲜多长时间。私有缓存会忽略 s-maxage
指令,并且如果存在,则会覆盖共享缓存中由 max-age
指令或 Expires
标头指定的值。
Cache-Control: s-maxage=604800
no-cache
no-cache
响应指令指示响应可以存储在缓存中,但每次重用之前都必须使用源服务器验证响应,即使缓存与源服务器断开连接也是如此。
Cache-Control: no-cache
如果希望缓存在重用存储的内容时始终检查内容更新,则应使用 no-cache
指令。它通过要求缓存使用源服务器重新验证每个请求来实现此目的。
请注意,no-cache
不表示“不要缓存”。no-cache
允许缓存存储响应,但要求它们在重用之前重新验证它。如果所需的“不要缓存”的含义实际上是“不要存储”,则应使用 no-store
指令。
must-revalidate
must-revalidate
响应指令指示响应可以存储在缓存中,并且可以在新鲜时重用。如果响应变得陈旧,则必须在重用之前使用源服务器对其进行验证。
通常,must-revalidate
与 max-age
一起使用。
Cache-Control: max-age=604800, must-revalidate
HTTP 允许缓存在与源服务器断开连接时重用陈旧响应。must-revalidate
是一种防止这种情况发生的方法——要么存储的响应使用源服务器重新验证,要么生成 504(网关超时)响应。
proxy-revalidate
proxy-revalidate
响应指令等效于 must-revalidate
,但仅针对共享缓存。
no-store
no-store
响应指令指示任何类型的缓存(私有或共享)都不应存储此响应。
Cache-Control: no-store
private
private
响应指令指示响应只能存储在私有缓存中(例如浏览器中的本地缓存)。
Cache-Control: private
您应该为用户个性化内容添加 private
指令,特别是对于登录后收到的响应以及通过 cookie 管理的会话。
如果您忘记向包含个性化内容的响应添加 private
,则该响应可能会存储在共享缓存中并最终被多个用户重用,这可能导致个人信息泄露。
public
public
响应指令指示响应可以存储在共享缓存中。具有 Authorization
标头字段的请求的响应不得存储在共享缓存中;但是,public
指令会导致此类响应存储在共享缓存中。
Cache-Control: public
通常,当页面处于基本身份验证或摘要身份验证下时,浏览器会发送带有 Authorization
标头的请求。这意味着响应对于受限用户(拥有帐户的用户)是访问受控的,并且从根本上来说不可共享缓存,即使它具有 max-age
也是如此。
您可以使用 public
指令来解除该限制。
Cache-Control: public, max-age=604800
请注意,s-maxage
或 must-revalidate
也会解除该限制。
如果请求没有 Authorization
标头,或者您已经在响应中使用了 s-maxage
或 must-revalidate
,则无需使用 public
。
must-understand
must-understand
响应指令指示缓存仅当它理解基于状态码的缓存要求时才应存储响应。
must-understand
应与 no-store
结合使用以实现回退行为。
Cache-Control: must-understand, no-store
如果缓存不支持 must-understand
,则会将其忽略。如果也存在 no-store
,则不会存储响应。
如果缓存支持 must-understand
,则会根据其状态码存储并理解缓存要求的响应。
no-transform
出于各种原因,某些中间体转换内容。例如,有些会转换图像以减小传输大小。在某些情况下,这对于内容提供者来说是不可取的。
no-transform
指示任何中间体(无论它是否实现缓存)都不应转换响应内容。
immutable
immutable
响应指令指示响应在其新鲜期间不会更新。
Cache-Control: public, max-age=604800, immutable
静态资源的现代最佳实践是在其 URL 中包含版本/哈希值,同时永远不修改资源——而是,在必要时,更新具有新版本号/哈希值的较新版本资源,以便它们的 URL 不同。这称为缓存清除模式。
<script src="https://example.com/react.0.0.0.js"></script>
当用户重新加载浏览器时,浏览器会发送条件请求以验证源服务器。但是,即使用户重新加载浏览器,也不需要重新验证这些类型的静态资源,因为它们从未修改过。immutable
告诉缓存响应在其新鲜期间是不可变的,并避免了对服务器进行此类不必要的条件请求。
当您对资源使用缓存失效模式并应用较长的max-age
时,还可以添加immutable
以避免重新验证。
stale-while-revalidate
stale-while-revalidate
响应指令指示缓存可以在重新验证到缓存时重用过期的响应。
Cache-Control: max-age=604800, stale-while-revalidate=86400
在上面的示例中,响应在7天(604800秒)内是新鲜的。7天后,它变为陈旧的,但缓存允许在接下来的1天(86400秒)内重用它,前提是在后台重新验证响应。
重新验证将使缓存再次变为新鲜的,因此在客户端看来,它在该期间始终是新鲜的——有效地隐藏了重新验证的延迟开销。
如果在此期间没有发生请求,则缓存变为陈旧的,并且下一个请求将正常重新验证。
stale-if-error
stale-if-error
响应指令指示缓存可以在上游服务器生成错误或本地生成错误时重用陈旧的响应。在此,错误被认为是任何状态代码为500、502、503或504的响应。
Cache-Control: max-age=604800, stale-if-error=86400
在上面的示例中,响应在7天(604800秒)内是新鲜的。之后,它变为陈旧的,但在遇到错误时可以额外使用1天(86400秒)。
在stale-if-error
期限过后,客户端将收到任何生成的错误。
请求指令
no-cache
no-cache
请求指令要求缓存在重用之前使用源服务器验证响应。
Cache-Control: no-cache
即使缓存有新鲜的响应,no-cache
也允许客户端请求最新的响应。
当用户**强制重新加载**页面时,浏览器通常会将no-cache
添加到请求中。
no-store
no-store
请求指令允许客户端请求缓存不要存储请求和相应的响应——即使源服务器的响应可以存储。
Cache-Control: no-store
max-age
max-age=N
请求指令指示客户端允许存储在源服务器上生成的响应,该响应在N秒内生成——其中N可以是任何非负整数(包括0
)。
Cache-Control: max-age=10800
在上述情况下,如果带有Cache-Control: max-age=10800
的响应是在3小时前(根据max-age
和Age
标头计算)生成的,则缓存无法重用该响应。
许多浏览器将此指令用于**重新加载**,如下所述。
Cache-Control: max-age=0
max-age=0
是no-cache
的解决方法,因为许多旧的(HTTP/1.0)缓存实现不支持no-cache
。最近,浏览器仍在“重新加载”中使用max-age=0
——为了向后兼容——并选择性地使用no-cache
来导致“强制重新加载”。
如果max-age
值为负数(例如,-1
)或不是整数(例如,3599.99
),则缓存行为未指定。鼓励缓存将该值视为0
。
max-stale
max-stale=N
请求指令指示客户端允许存储在N秒内陈旧的响应。如果没有指定N值,则客户端将接受任何年龄的陈旧响应。
Cache-Control: max-stale=3600
例如,带有上述标头的请求指示浏览器将接受来自缓存的陈旧响应,该响应在过去一小时内已过期。
当源服务器宕机或速度过慢时,客户端可以使用此标头,并且即使缓存响应有点旧,也可以接受来自缓存的缓存响应。
请注意,主流浏览器不支持带有max-stale
的请求。
min-fresh
min-fresh=N
请求指令指示客户端允许存储至少N秒内新鲜的响应。
Cache-Control: min-fresh=600
在上述情况下,如果带有Cache-Control: max-age=3600
的响应是在51分钟前存储在缓存中的,则缓存无法重用该响应。
当用户不仅需要响应新鲜,而且还需要它在一段时间内不会更新时,客户端可以使用此标头。
请注意,主流浏览器不支持带有min-fresh
的请求。
no-transform
与响应的no-transform
含义相同,但用于请求。
only-if-cached
客户端指示应返回已缓存的响应。如果缓存有存储的响应,即使是陈旧的响应,也会返回。如果没有可用的缓存响应,将返回504网关超时响应。
用例
防止存储
如果您不希望响应存储在缓存中,请使用no-store
指令。
Cache-Control: no-store
请注意,no-cache
表示“可以存储,但在验证之前不要重用”——因此它不是为了防止响应被存储。
Cache-Control: no-cache
理论上,如果指令发生冲突,则应遵循最严格的指令。因此,下面的示例基本上毫无意义,因为private
、no-cache
、max-age=0
和must-revalidate
与no-store
冲突。
# conflicted
Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate
# equivalent to
Cache-Control: no-store
使用“缓存失效”缓存静态资源
当您使用版本控制/哈希机制构建静态资源时,在文件名或查询字符串中添加版本/哈希是管理缓存的好方法。
例如
<!-- index.html -->
<script src="/assets/react.min.js"></script>
<img src="/assets/hero.png" width="900" height="400" />
当您更新库时,React库版本将发生变化,并且当您编辑图片时,hero.png
也将发生变化。因此,很难使用max-age
将它们存储在缓存中。
在这种情况下,您可以通过使用库的特定编号版本并在其URL中包含图片的哈希来解决缓存需求。
<!-- index.html -->
<script src="/assets/react.0.0.0min.js"></script>
<img src="/assets/hero.png?hash=deadbeef" width="900" height="400" />
您可以添加较长的max-age
值和immutable
,因为内容永远不会更改。
# /assets/*
Cache-Control: max-age=31536000, immutable
当您更新库或编辑图片时,新内容应具有新的URL,并且不会重用缓存。这称为“缓存失效”模式。
使用no-cache
确保HTML响应本身不会被缓存。no-cache
可能会导致重新验证,并且客户端将正确接收HTML响应和静态资源的新版本。
# /index.html
Cache-Control: no-cache
注意:如果index.html
受基本身份验证或摘要身份验证控制,则/assets
下的文件不会存储在共享缓存中。如果/assets/
文件适合存储在共享缓存中,则还需要public
、s-maxage
或must-revalidate
之一。
始终获取最新的内容
对于动态生成的内容或静态但经常更新的内容,您希望用户始终接收最新版本。
如果您不添加Cache-Control
标头,因为响应并非旨在缓存,则可能会导致意外结果。缓存存储允许启发式地缓存它——因此,如果您对缓存有任何要求,则应始终在Cache-Control
标头中明确指示它们。
向响应中添加no-cache
会导致重新验证服务器,因此您可以每次都提供新鲜的响应——或者如果客户端已经有了新的响应,则只需响应304 未修改
。
Cache-Control: no-cache
大多数HTTP/1.0缓存不支持no-cache
指令,因此历史上使用max-age=0
作为解决方法。但是,只有max-age=0
才能导致在缓存与源服务器断开连接时重用陈旧的响应。must-revalidate
解决了这个问题。这就是下面示例等效于no-cache
的原因。
Cache-Control: max-age=0, must-revalidate
但现在,您可以简单地使用no-cache
。
清除已存储的缓存
不幸的是,没有用于清除缓存中已存储响应的缓存指令。
假设客户端/缓存存储了路径的新鲜的响应,而没有向服务器发送请求。服务器对此路径无能为力。
或者,Clear-Site-Data
可以清除浏览器的站点缓存。但请注意:这将清除站点的所有存储的响应——并且仅在浏览器中,而不是在共享缓存中。
规范
规范 |
---|
HTTP缓存 # field.cache-control |
HTTP不可变响应 # the-immutable-cache-control-extension |
浏览器兼容性
BCD表格仅在启用JavaScript的浏览器中加载。