用于缓存的新HTTP标准:Cache-Status和Target-Cache-Control


互联网工程任务组 (IETF) 的 HTTP 工作组最近发布了两个新的 HTTP 标头草案标准,目标是调试缓存更容易,并提供对缓存配置的更多控制。
两个拟议标准是:


这些旨在更新 HTTP 标准以匹配当今存在的 CDN 支持的网络的现实,创建规范以形式化流行 CDN(如 Fastly、Akamai 和 Cloudflare,所有这些人都参与编写标准本身)的现有实践)。
这两个都是相当新的规范:Cache-Status 已经在 2021 年完成了多轮审查,目前正在等待(自 8 月以来)作为正式 RFC 的最终审查和发布,而 Targeted Cache-Control Headers 目前是一个采用的标准草案,但是在最后一次征求反馈意见中。在这两种情况下,它们都得到了 IETF 的支持,它们已经收到了很多讨论,而且在这一点之后它们不太可能会有太大变化。
 
Cache-Status 将如何提供帮助?
互联网上缓存明显的问题之一是多个缓存/CDN系统之间的可追溯性。对于给定的响应,它到底来自哪里,经过多少CDN?
这个响应是来自缓存还是来自真实服务器?如果它来自缓存,是哪个缓存?它会继续这样做多久?如果它不是来自缓存,为什么不呢?是否存储了此新响应以供以后使用?
Cache-Status响应报头提供了一种系列缓存信息的结构,所有缓存信息被包含在其中都是以一致的格式的提供,这些信息包括响应内容本身,所有CDN或其他能看见该请求的缓存信息。
格式:
Cache-Status: CacheName; param; param=value; param..., CacheName2; param; param...

如下是一个实例:
Cache-Status: OriginCache; hit; ttl=1100, "CDN Company Here"; fwd=uri-miss;

它是一系列缓存,每个缓存都有零个或多个状态参数。缓存按响应顺序排列:第一个缓存是最靠近源服务器的缓存,最后一个缓存是最靠近客户端的缓存。
值得注意的是,响应可能会与此标头一起保存在缓存中,并且会保留在未来的响应中。尽管如此,还是可以使用从右侧读取的参数来了解这次响应具体存储在哪里,以及它之前来自哪里。
此处的带参数缓存值用逗号分隔,而参数本身用分号分隔(这是现在标准化的结构化标头 RFC 中的sf-listandsf-item语法),当缓存名称包含其他无效时,可以引用它们空格等字符。
参数定义:

  • hit - 响应来自此缓存,而没有向上游发送请求
  • fwd=<reason>- 如果设置,请求被向上发送到下一层。这是有原因的:
    • fwd=bypass - 缓存配置为不处理此请求
    • fwd=method - 由于使用的 HTTP 方法,必须转发请求
    • fwd=uri-miss - 请求 URI 没有可用的匹配缓存数据
    • fwd=vary-miss- URI 有匹配的缓存数据,但Vary标头中列出的标头不匹配
    • fwd=miss - 没有匹配的缓存数据可用(出于其他原因,例如,如果缓存不确定原因)
    • fwd=stale - 有匹配的缓存数据,但它是陈旧的
    • fwd=partial- 存在匹配的缓存数据,但仅针对部分响应(例如,先前的请求使用了Range标头)
    • fwd=request - 请求请求的非缓存数据(例如在其 Cache-Control 标头中)
  • fwd-status=<status>- 如果fwd设置,这是从下一跳收到的响应状态
  • stored- 如果fwd已设置,则表示接收到的响应是否由此缓存存储以备后用
  • collapsed- 如果fwd设置了,这表示请求是否被另一个请求折叠(即不重复,因为等效的请求已经在处理中)
  • ttl=<ttl> - 此缓存将将此响应视为“新鲜”的时间(以秒为单位)多长时间
  • key - 此缓存中响应的(特定于实现的)键
  • detail - 一个额外的自由格式字段,用于附加特定于实现的信息

使用这些,我们可以解释响应头,如:

Cache-Status: ExampleCache; hit; ttl=30; key=/abc

这意味着 ExampleCache 收到了请求,它在其缓存中(在key/abc 下)找到了一个响应并将其返回,并希望在接下来的 30 秒内继续这样。

....
  
Targeted Cache-Control
现有的Cache-Control 标头是在更简单的时间(1999 年)设计的。今天响应的 Cache-Control 定义了一个指令列表,这些指令告诉缓存如何处理响应,如下所示:
 

Cache-Control: max-age=600, stale-while-revalidate=300, private

这意味着“将此内容缓存 10 分钟,然后在您尝试重新验证它时再提供最多 5 分钟的旧内容,但只能在私人(单用户,例如浏览器)缓存中执行此操作”。
这有点生硬——处理请求的所有缓存必须以完全相同的方式遵循此处设置的规则。
引入Targeted Cache-Control新标头可设置仅针对特定缓存而非所有缓存的缓存控制指令来解决此问题。

<Target>-Cache-Control: param, param=value, param...

标头以应适用的特定目标为前缀。该语法在技术上与 Cache-Control 使用的语法略有不同,因为它现在使用标准的结构化字段格式,但实际上几乎相同。
Targeted 可能是唯一的服务或组件名称,或一整类缓存。规范仅定义了一个目标 - CDN-Cache-Control,它应该适用于所有分布式 CDN 缓存,但不适用于其他缓存 - 但可以稍后定义其他类。将来,您可以想象Client-Cache-Control仅为 HTTP 客户端、ISP-Cache-Control等。
如果您已经熟悉现有的缓存机制,那么这非常简单且易于使用。目标标头匹配某些目标,您可以根据需要配置每个目标的缓存规则,最佳匹配获胜。例如:

Client-Cache-Control: must-revalidate
CDN-Cache-Control: max-age=600, stale-after-revalidate=300
Squid-Cache-Control: max-age=60
Cache-Control: no-store

说明如下:

  • 终端客户端(至少,那些识别出Client-Cache-Control我刚刚制作的标头的客户端)可以缓存此内容,但每次使用前都必须重新验证它
  • 所有 CDN 都可以将内容缓存 10 分钟,然后使用过时的响应同时重新验证它额外的 5 分钟
  • Squid(缓存反向代理)只能缓存 60 秒的内容(并且在它过时时隐式不能使用它,因为没有stale-while-revalidate指令)
  • 任何其他人或任何不理解目标缓存控制指令的人都绝对不能缓存此内容。

 
新规范本身就在此处的GitHub 上,您可以在该存储库中提交问题(或向工作组邮件列表发送消息)以分享您的想法。