Skip to content

Hypertext Transfer Protocol (HTTP/1.1): Caching

1. Introduction

HTTP 是一种无状态的应用层协议,常用于分布式信息系统中。通过使用响应缓存,可以显著提高性能。本文件定义了 HTTP 缓存及其相关的控制缓存行为或指示可缓存响应消息的头字段。

HTTP 缓存是一个本地存储响应消息的子系统,控制存储、检索和删除消息。缓存存储可缓存的响应,以减少未来等效请求的响应时间和网络带宽消耗。任何客户端或服务器都可以使用缓存,但作为隧道的服务器不能使用缓存。

缓存分为共享缓存和私有缓存。共享缓存存储的响应可以被多个用户重用,而私有缓存则专用于单个用户。

HTTP/1.1 中缓存的目标是通过重复使用先前的响应消息来满足当前请求,从而显著提高性能。一个存储的响应被认为是“新鲜的”,如果可以在不验证的情况下重用。新鲜的响应每次重用都可以减少延迟和网络开销。

2. Overview of Cache Operation

正确的缓存操作在消除缓存中已有信息传输的同时,保留了 HTTP 传输的语义。虽然缓存是 HTTP 的一个完全可选的功能,但可以假设重用缓存响应是有利的,并且在没有要求或本地配置阻止的情况下,这种重用是默认行为。因此,HTTP 缓存要求侧重于防止缓存存储不可重用的响应或不适当重用存储的响应,而不是强制缓存总是存储和重用特定响应。

每个缓存条目由一个缓存键和一个或多个 HTTP 响应组成,这些响应对应于使用相同键的先前请求。最常见的缓存条目形式是检索请求的成功结果,例如对 GET 请求的 200 (OK) 响应,其中包含请求目标标识的资源的表示。

3. Storing Responses in Caches

缓存不得存储对任何请求的响应,除非满足以下条件:

  • 请求方法被缓存理解并定义为可缓存的;
  • 响应状态代码被缓存理解;
  • 请求或响应头字段中没有出现“no-store”缓存指令;
  • 如果缓存是共享的,响应中没有出现“private”响应指令;
  • 如果缓存是共享的,请求中没有出现 Authorization 头字段,除非响应明确允许;
  • 响应包含 Expires 头字段,或包含 max-age 响应指令,或包含 s-maxage 响应指令且缓存是共享的,或包含允许其被缓存的缓存控制扩展,或具有默认可缓存的状态代码,或包含 public 响应指令。

4. Constructing Responses from Caches

当缓存收到请求时,除非满足以下条件,否则不得重用存储的响应:

  • 请求的有效 URI 与存储的响应匹配;
  • 与存储响应关联的请求方法允许用于当前请求;
  • 存储的响应中提名的选择头字段(如果有)与当前请求中的匹配;
  • 当前请求中不包含 no-cache pragma 或 no-cache 缓存指令,除非存储的响应成功验证;
  • 存储的响应不包含 no-cache 缓存指令,除非成功验证;
  • 存储的响应是新鲜的,或允许提供过期的响应,或成功验证。

5. Header Field Definitions

5.1. Age

"Age" 头字段传达发送者对响应生成或在源服务器成功验证以来经过时间的估计值。Age 值按秒表示。

5.2. Cache-Control

"Cache-Control" 头字段用于指定请求/响应链中缓存的指令。缓存必须遵守本节定义的 Cache-Control 指令。

5.2.1. Request Cache-Control Directives

  • max-age: 指示客户端不愿接受超过指定秒数的响应。
  • max-stale: 指示客户端愿意接受超过其新鲜度生命周期的响应。
  • min-fresh: 指示客户端愿意接受其新鲜度生命周期不少于当前年龄加上指定秒数的响应。
  • no-cache: 指示缓存不得在没有成功验证的情况下使用存储的响应。
  • no-store: 指示缓存不得存储请求或响应的任何部分。
  • no-transform: 指示中间人不得转换负载。
  • only-if-cached: 指示客户端只希望获得存储的响应。

5.2.2. Response Cache-Control Directives

  • must-revalidate: 指示一旦响应变得过期,缓存不得在没有成功验证的情况下使用响应。
  • no-cache: 指示响应不得在没有成功验证的情况下用于后续请求。
  • no-store: 指示缓存不得存储请求或响应的任何部分。
  • no-transform: 指示中间人不得转换负载。
  • public: 指示任何缓存可以存储响应,即使响应通常不可缓存或仅在私有缓存中可缓存。
  • private: 指示响应消息仅用于单个用户,且不得由共享缓存存储。
  • proxy-revalidate: 与 must-revalidate 指令相同,但不适用于私有缓存。
  • max-age: 指示响应在其年龄超过指定秒数后变得过期。
  • s-maxage: 在共享缓存中,指定的最大年龄覆盖 max-age 指令或 Expires 头字段指定的最大年龄。

5.3. Expires

"Expires" 头字段给出了响应被认为过期的日期/时间。

5.4. Pragma

"Pragma" 头字段允许与 HTTP/1.0 缓存向后兼容,以便客户端可以指定“no-cache”请求。

5.5. Warning

"Warning" 头字段用于传递关于消息状态或转换的附加信息,通常用于警告缓存操作或对消息负载应用的转换可能引入的不正确性。

5.5.1. Warning: 110 - "Response is Stale"

缓存应在发送过期响应时生成此警告。

5.5.2. Warning: 111 - "Revalidation Failed"

缓存应在尝试验证响应失败时发送过期响应时生成此警告。

5.5.3. Warning: 112 - "Disconnected Operation"

缓存应在有意与网络断开连接一段时间时生成此警告。

5.5.4. Warning: 113 - "Heuristic Expiration"

如果缓存启发式选择了超过 24 小时的新鲜度生命周期且响应的年龄超过 24 小时,缓存应生成此警告。

6. History Lists

用户代理通常具有历史机制,例如“后退”按钮和历史列表,可以用于重新显示会话中早先检索的表示。历史机制可以显示先前的表示,即使它已过期。

7. IANA Considerations

7.1. Cache Directive Registry

“Hypertext Transfer Protocol (HTTP) Cache Directive Registry”定义了缓存指令的命名空间。

7.2. Warn Code Registry

“Hypertext Transfer Protocol (HTTP) Warn Codes”注册表定义了警告代码的命名空间。

7.3. Header Field Registration

HTTP 头字段在“Message Headers”注册表中注册。

8. Security Considerations

缓存增加了潜在的漏洞,因为缓存内容对恶意利用具有吸引力。缓存内容在 HTTP 请求完成后仍然存在,因此对缓存的攻击可能会在用户认为信息已从网络中删除后很长时间内揭示信息。因此,缓存内容需要像敏感信息一样受到保护。

ABNF

abnf
Age = delta-seconds

Cache-Control = *( "," OWS ) cache-directive *( OWS "," [ OWS cache-directive ] )

Expires = HTTP-date

HTTP-date = <HTTP-date, see [RFC7231], Section 7.1.1.1>

OWS = <OWS, see [RFC7230], Section 3.2.3>

Pragma = *( "," OWS ) pragma-directive *( OWS "," [ OWS pragma-directive ] )

Warning = *( "," OWS ) warning-value *( OWS "," [ OWS warning-value ] )

cache-directive = token [ "=" ( token / quoted-string ) ]

delta-seconds = 1*DIGIT

extension-pragma = token [ "=" ( token / quoted-string ) ]

field-name = <field-name, see [RFC7230], Section 3.2>

port = <port, see [RFC7230], Section 2.7>
pragma-directive = "no-cache" / extension-pragma
pseudonym = <pseudonym, see [RFC7230], Section 5.7.1>

quoted-string = <quoted-string, see [RFC7230], Section 3.2.6>

token = <token, see [RFC7230], Section 3.2.6>

uri-host = <uri-host, see [RFC7230], Section 2.7>

warn-agent = ( uri-host [ ":" port ] ) / pseudonym
warn-code = 3DIGIT
warn-date = DQUOTE HTTP-date DQUOTE
warn-text = quoted-string
warning-value = warn-code SP warn-agent SP warn-text [ SP warn-date ]