互联网工程任务组 (IETF) S. Ludin
请求评议:9213 Akamai
类别:标准轨道 M. Nottingham
ISSN: 2070-1721 Fastly
Y. Wu
Cloudflare
June 2022

定向 HTTP 缓存控制


摘要

本规范定义了一种约定,用于在 HTTP 响应头字段中允许将缓存指令定向到特定缓存或某类缓存。它还定义了其中一个此类头字段 —— 面向内容分发网络 (CDN) 缓存的 CDN-Cache-Control 响应头字段。

本备忘录的状态

这是一个互联网标准轨道文档。

本文件是互联网工程任务组 (IETF) 的成果,代表 IETF 社区的共识。它已获得公开评审,并由互联网工程指导小组 (IESG) 批准发布。关于互联网标准的更多信息请参见 RFC 7841 第2节

关于本文档当前状态、勘误及如何反馈信息,可访问 https://www.rfc-editor.org/info/rfc9213 获取。

Copyright Notice

Copyright (c) 2022 IETF Trust and the persons identified as the document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.


1. 引言

现代的 HTTP 部署通常使用多层缓存。例如,网站可能在源服务器本身使用缓存;可能在与源服务器相同的网络中部署一个缓存层;可能使用一个或多个分布在互联网上的 CDN;也可能受益于浏览器缓存。

由于通常希望分别控制这些不同类别的缓存,因此需要某种将缓存指令定向到它们的手段。例如,如果发布者具有使其相关缓存(如 CDN 缓存)内容失效的机制,他们可能会更愿意为该缓存分配更宽松的缓存策略,同时仍希望限制其他缓存的行为。

HTTP 的 Cache-Control 响应头字段(定义见 Section 5.2 of [HTTP-CACHING])被广泛用于指导缓存行为。但它相对不具区分性;虽然某些缓存指令(例如 s-maxage)针对特定类别的缓存(如共享缓存),但并非所有现有缓存指令都能一致地进行定向(例如 stale-while-revalidate)。随着缓存扩展数量和潜在目标数量的增长,这会带来问题。

一些实现已经定义了临时的控制机制来克服此问题,但它们的互操作性较低。第 2 节 定义了一个使用 HTTP 响应头进行定向缓存控制的标准框架,而 第 3 节 定义了其中的一个头字段:CDN-Cache-Control 响应头字段。

1.1. 符号约定

文中关键词 "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", 和 "OPTIONAL" 应按 BCP 14 [RFC2119][RFC8174] 的说明来解释,仅在这些词以全大写形式出现时适用。


2. 定向 Cache-Control 头字段

Targeted Cache-Control Header Field(下称“定向字段”)是一个具有与 Cache-Control 响应头字段相同语义的 HTTP 响应头字段(见 [HTTP-CACHING]Section 5.2)。然而,它具有一个不同的字段名,用以指示其缓存指令的目标。

例如:

CDN-Cache-Control: max-age=60

是一个针对 CDN 的定向字段,如 第 3 节 所定义。

2.1. 语法

定向字段是 Dictionary Structured Fields(RFC8941 第 3.2 节)。字典的每个成员都是一个 HTTP 缓存响应指令(见 RFC9111 第 5.2.2 节),包括扩展响应指令(见 RFC9111 第 5.2.3 节)。注意,尽管定向字段通常具有与 Cache-Control 字段相同的语法,但错误处理差异意味着使用 Cache-Control 解析器而不是 Structured Fields 解析器可能会引入互操作性问题。

由于缓存指令未以结构化数据类型定义,必须将其值映射到适当的类型。RFC9111 第 5.2 节 定义了缓存指令值可以是缺省、带引号字符串或 token。

这意味着没有值的缓存指令将映射为 Boolean(参见 RFC8941 第 3.3.6 节)。当值为带引号字符串时,映射为 String(参见 RFC8941 第 3.3.3 节);当值为 token 时,根据内容可映射为 Token、Integer(参见 RFC8941 第 3.3.1 节)或 Decimal(参见 RFC8941 第 3.3.2 节)。

例如,max-age 指令(见 RFC9111 第 5.2.2.1 节)具有整数值;no-store(见 RFC9111 第 5.2.2.5 节)始终为 Boolean true;no-cache(见 RFC9111 第 5.2.2.4 节)的值可以是 Boolean true 或包含以逗号分隔的字段名列表的字符串。

实现 不得 生成违反这些推断约束的缓存指令值。特别地,若字符串值的首字符不是字母或 "*",则 必须 作为 Strings 生成,以免被误判为其他类型。

实现 不应 消费违反这些推断约束的值。例如,将带小数的 max-age 强制转换为整数的消费实现,会与其他实现行为不同,可能引发互操作性问题。

在缓存指令上收到的参数应被忽略,除非另有明确规定。

如果响应中的定向字段为空,或在解析时遇到错误,则该字段 必须 被缓存忽略(即表现得好像该字段不存在,通常回退到响应中存在的其他 cache-control 机制)。

2.2. 缓存行为

实现本规范的缓存维护一个目标列表。目标列表是一个有序的定向字段名列表,缓存使用该列表来决定缓存策略,列表顺序表示从最适用到最不适用的优先级。目标列表可以是固定的、用户可配置的,或按请求生成,取决于实现。

例如,某个 CDN 缓存可能同时支持 CDN-Cache-Control 和 针对该 CDN 的头字段 ExampleCDN-Cache-Control,后者覆盖前者。其目标列表可能是:

  [ExampleCDN-Cache-Control, CDN-Cache-Control]
  

当实现本规范的缓存收到包含其目标列表中一个或多个头字段名的响应时,缓存 必须 选择目标列表中第一个(按顺序)具有有效且非空值的字段,并使用其值来确定该响应的缓存策略;并且缓存 必须 忽略响应中的 Cache-Control 和 Expires 头字段,除非在列出的头字段中没有可用的有效非空值。

注意这是逐响应发生的;如果缓存的目标列表中没有任何成员存在、有效且非空,则缓存按照 HTTP 的要求回退到其他缓存控制机制(见 [HTTP-CACHING])。

不在缓存目标列表内的定向字段 不得 改变该缓存的行为,且 必须 被透传。

使用定向字段的缓存 必须 实现下列缓存指令的语义:

  • max-age
  • must-revalidate
  • no-store
  • no-cache
  • private

此外,它们 实现它们在 Cache-Control 响应头字段中支持的其他缓存指令(包括扩展缓存指令)。

定向字段中缓存指令的语义和优先级与 Cache-Control 中相同。特别地,no-store 和 no-cache 会使 max-age 无效,未识别的扩展指令将被忽略。

2.3. 与 HTTP 新鲜度的交互

HTTP 缓存具有端到端的新鲜度模型,定义见 RFC9111 第 4.2 节。当某些缓存路径上的缓存只有针对它们可用的额外新鲜度机制(例如使用定向字段)时,需要谨慎考虑它们的交互。特别地,定向缓存可能具有比其他缓存更长的新鲜期,导致它向下游缓存或客户端提供的响应对其他缓存来说显得过早(甚至立即)过期,从而负面影响缓存效率。

例如,某个 CDN 缓存存储的响应可能带有如下头字段:

Age: 1800
Cache-Control: max-age=600
CDN-Cache-Control: max-age=3600

从 CDN 的角度看,该响应在缓存 30 分钟后仍然是新鲜的,而从其他缓存的角度,该响应已经是陈旧的。有关更多讨论,请参见 [AGE-PENALTY]

当定向缓存具有强一致性机制(例如源服务器能够主动使缓存失效)时,通常希望缓解这些影响。部署中见到的一些技术包括:

  • 移除 Age 首部字段
  • 将 Date 首部字段更新为当前时间
  • 将 Expires 首部字段更新为当前时间,加上任何 Cache-Control: max-age 值

本规范对实现缓解这些影响不作具体要求,但定向字段的定义可以包含此类要求。

2.4. 定义定向字段

针对特定缓存类别的定向字段可以通过在 "Hypertext Transfer Protocol (HTTP) Field Name Registry"(<https://www.iana.org/assignments/http-fields/>)中请求注册来定义。

注册请求可以使用本文档作为规范文档;在这种情况下,Comments 字段应明确定义该定向字段适用的缓存类别。或者,如果已有其他文档定义该字段,也可使用该文档作为规范文档。

按惯例,定向字段带有后缀 "-Cache-Control",例如 "ExampleCDN-Cache-Control"。然而,该后缀 不得 单独用来识别定向字段;它仅为一种惯例。


3. CDN-Cache-Control 定向字段

CDN-Cache-Control 响应头字段是一个定向字段(见 第 2 节),它允许源服务器单独控制插入在源与客户端之间的 CDN 缓存的行为,而不影响可能处理该响应的其他缓存。

它适用于作为分布式网络一部分、代表源服务器运行的缓存(通常称为 CDN)。

使用 CDN-Cache-Control 的 CDN 缓存通常会转发该头,以便下游的 CDN 缓存也能使用它。但在不希望转发的情况下(例如已配置为下游不会使用时),它们 可以 将其移除。

3.1. 示例

例如,以下头字段会指示 CDN 缓存(即目标列表为 [CDN-Cache-Control] 的缓存)将响应视为 600 秒内新鲜,其他共享缓存将视为 120 秒新鲜,其余缓存视为 60 秒新鲜:

Cache-Control: max-age=60, s-maxage=120
CDN-Cache-Control: max-age=600

这些头字段会指示 CDN 缓存将响应视为 600 秒新鲜,而所有其他缓存则被阻止存储该响应:

CDN-Cache-Control: max-age=600
Cache-Control: no-store

如果不存在 CDN-Cache-Control,则以下头字段会阻止所有缓存存储该响应:

Cache-Control: no-store

而下面这些会阻止除 CDN 缓存之外的所有缓存存储该响应:

Cache-Control: no-store
CDN-Cache-Control: none

(注意 'none' 不是注册的缓存指令;此处使用它是为了避免发送空值的头字段,因为空值的头字段会被忽略。)


4. IANA 注意事项

IANA 已在 [HTTP] 定义的 "Hypertext Transfer Protocol (HTTP) Field Name Registry" 中注册了以下条目:

Field Name:
CDN-Cache-Control
Status:
permanent
Specification Document:
RFC 9213
Comments:
针对内容分发网络的缓存指令

5. 安全性注意事项

适用于 HTTP 缓存的安全性注意事项仍然适用(见 [HTTP-CACHING])。

在响应上携带多种缓存策略的能力可能会导致关于响应在不同系统中如何被缓存的混淆,可能导致包含敏感信息的响应被无意间重用。因此必须谨慎处理。

6. 参考文献

6.1. 规范性引用

[HTTP]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., “HTTP Semantics”, STD 97, RFC 9110, DOI 10.17487/RFC9110, June 2022, <https://www.rfc-editor.org/info/rfc9110>.
[HTTP-CACHING]
Fielding, R., Ed., Nottingham, M., Ed., and J. Reschke, Ed., “HTTP Caching”, STD 98, RFC 9111, DOI 10.17487/RFC9111, June 2022, <https://www.rfc-editor.org/info/rfc9111>.
[RFC2119]
Bradner, S., “Key words for use in RFCs to Indicate Requirement Levels”, BCP 14, RFC 2119, DOI 10.17487/RFC2119, March 1997, <https://www.rfc-editor.org/info/rfc2119>.
[RFC8174]
Leiba, B., “Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words”, BCP 14, RFC 8174, DOI 10.17487/RFC8174, May 2017, <https://www.rfc-editor.org/info/rfc8174>.
[STRUCTURED-FIELDS]
Nottingham, M. and P-H. Kamp, “Structured Field Values for HTTP”, RFC 8941, DOI 10.17487/RFC8941, February 2021, <https://www.rfc-editor.org/info/rfc8941>.

作者地址

Stephen Ludin
Akamai
EMail: sludin@ludin.org
Mark Nottingham
Fastly
Prahran
Australia
EMail: mnot@mnot.net
URI: https://www.mnot.net/
Yuchen Wu
Cloudflare
EMail: me@yuchenwu.net