介绍缓存响应规则

发布于

**今天我们很高兴地宣布缓存响应规则。** 这是一种新的规则类型,它在源服务器响应后运行,但在 Cloudflare 缓存内容之前运行。

如果你曾因某些内容因为多余的 `Set-Cookie` 或错误的 `Cache-Control` 而无法方便缓存而感到恼火,缓存响应规则即是在正确的时机解决这个问题。

## 缓存决策的时间与方式

CDN 缓存与源服务器相辅相成。他们的目标是尽可能从缓存中响应,仅在边缘无法响应时才回到源。每一项缓存命中率都来自于正确的劳动分工。如果在不该检查缓存的时候检查,我们就浪费了一个本来会跳过的查找。如果检查得太少,源反而可以处理边缘应该吸收的流量,从而降低性能。

重要的是,源指导着缓存。当源返回一个可缓存的资产时,其响应头告诉 Cloudflare 多长时间可以提供它,何时以及如何重新验证,甚至是否可以缓存。当源错误时,缓存只是装饰,而源基础设施的费用急剧上升。

大多数缓存资格问题并不是在请求时决定的,而是在源响应之后显现的。

一个访客请求 `/static/app.js`。Cloudflare 检查缓存,未命中,并将请求转发给源。源返回文件。在那些响应头中,安静地存在着一个 `Set-Cookie` 头。这个应该在每个 Cloudflare 数据中心都可以缓存的资产,现在变得不可缓存了。乘以每个访客、每个站点,带有相同意外头部的情况,你就有了一个导致源带宽泄漏、降低性能并推高基础设施成本的缓存命中率。

这种问题有许多变化。源在本该可以在 CDN 上缓存的资产上发送 `Cache-Control: no-cache`。源发送正确的指令,但它们是面向浏览器的,而不是 Cloudflare 的。或者源附加一个过于激进的 `ETag`(特定版本资源的标识符),在每个条件请求上造成重新验证的混乱。尤其是在大型团队中,管理源响应的团队与管理 CDN 的团队通常是不同的。这使得改变一行头部的过程需要几周的时间谈判。

这些问题都无法在请求时间解决。当 Cloudflare 看到 `/app.js` 上的 `Set-Cookie` 时,请求阶段已经结束,响应已经在传输中。

因此,我们在合适的地方加入了修复。

**缓存响应规则在源的响应到达 Cloudflare 后运行,但在写入缓存之前。** 使用它们,您可以重写 `Cache-Control` 指令,管理缓存标签,并在 Cloudflare 的缓存看到响应之前删除 `Set-Cookie`、`ETag` 和 `Last-Modified` 等头部。这个修复完全存在于 Cloudflare 上,无需修改源代码。

## 缺失的环节

如果你在 Cloudflare 使用了一段时间,你可能注意到缓存控制的表面区域不断演变。几年前,这一切主要存在于 [**页面规则**](https://developers.cloudflare.com/rules/page-rules/),它作为一个单一的、负载过重的规则,混合了缓存、重定向、安全以及其他许多行为,所有这些都是在请求时进行评估的。后来我们 [**分离了这些规则**](https://blog.cloudflare.com/future-of-page-rules/) ,使得只有相关的行为变化会在请求时进行评估,减少了不必要的延迟,并允许在不同的行为之间进行复杂的规则堆叠。[**缓存规则**](https://developers.cloudflare.com/cache/how-to/cache-rules/) 成为专门针对缓存决策的表达性规则类型,随后又加入了 [**CDN-Cache-Control**](https://developers.cloudflare.com/cache/concepts/cdn-cache-control/)、[**源缓存控制**](https://developers.cloudflare.com/cache/concepts/cache-control/) 、[**自定义缓存键**](https://developers.cloudflare.com/cache/how-to/cache-rules/examples/custom-cache-key/) 和其他控件,这些都为你提供了精确的方式来告知 Cloudflare 什么是安全缓存的、缓存多久以及在什么条件下。

这些控件有一个共同点:它们都是在 **请求** 上运行的。

虽然这可能不合逻辑,但实际上是有道理的。Cloudflare 需要做出的最重要的缓存决策是 **我们应该在缓存中查找吗?在什么键下?** 这个问题必须在 Cloudflare 与源联系之前得到解答。如果答案是“否”,而它应该是“是”,请求已经为源的往返花费了时间,响应无法弥补这段延迟。请求时间规则使用当时唯一可用的信息:URL、请求文件的扩展名、请求头、地理位置、设备类型等等。通过这些请求参数和设置以改变这些请求参数的规则,我们判断某些内容是否可能在缓存中,然后在与源交谈之前查看缓存。

但是,某些缓存决策无法在请求时做出。源的 `Cache-Control` 指令(例如 cache-control: max-age=3600)是 Cloudflare 从源接收的响应的一部分。状态码、ETag、Last-Modified 时间戳、Set-Cookie 和源选择的缓存标签格式都是传递到缓存中的响应内容。如果请求时间规则运行时没有这些信息,响应的内容就是唯一的真实来源,因此如果有需要在 Cloudflare 上更改的内容但在请求时间不可用,那么你以前只能用三个解决方案:
1. 更改源。
2. 编写 Worker 重新获取并重写响应。
3. 忍受较差的命中率。
每一个解决方案都需要工程时间、增加延迟,或者增加成本。**缓存响应规则为你提供了第四个选项:一个规则集,你可以在响应到达 Cloudflare 的缓存之前修改源的响应。**

## 两个阶段,两个问题

最简洁的方式来理解 [**缓存规则**](https://developers.cloudflare.com/cache/how-to/cache-rules/) 与新的 [**缓存响应规则**](https://developers.cloudflare.com/cache/how-to/cache-response-rules/) 之间的区别是将它们视为两个阶段,每个阶段回答自己的问题。

- **缓存规则** 在请求阶段运行,**在 Cloudflare 与源服务器对话之前**。它们的回答是:**鉴于这个请求,Cloudflare 应该缓存响应吗?用什么缓存键?** 有三个决策可以在请求时间用缓存规则做出:**是否**缓存(合格与绕过)、**对象**是什么(缓存键及如何识别存储对象)以及**如何**缓存(边缘 TTL、浏览器 TTL、过期服务等)。所有这些问题必须在访问源之前解决,仅使用请求中的信息。

- **缓存响应规则** 在响应阶段运行,在源响应后但在响应写入 Cloudflare 缓存之前。缓存响应规则回答:**现在源已经响应,我们应该调整如何缓存它吗?** 缓存响应规则可以通过**去除会使响应不合格的头部**、**更改源 `cache-control` 指令告知 Cloudflare 是否以及如何缓存**,或者**设置用于删除内容的缓存标签**来重写请求中的“如何”。当缓存规则与缓存响应规则发生冲突时,缓存响应规则胜出。

响应阶段无法做到请求阶段所能做的一切。它无法更改 **什么**,因为键已经固定。但它可以改变 **是否** 和 **如何** Cloudflare 缓存,例如,响应规则可以设置 `no-store` 使可缓存对象变为不可缓存,或去除 `Set-Cookie` 使不可缓存内容具有缓存资格。然而,缓存响应规则不能使在请求阶段不可缓存的内容在响应阶段变得可缓存,因为已经太晚了。

因此缓存响应规则并不替代缓存规则。缓存规则决定 **我们在请求时是否、什么内容和如何** 缓存。缓存响应规则在 Cloudflare 看到源的响应时获得最终发言权。

## 你可以做什么

缓存响应规则今天支持三项操作:
1. **去除会破坏缓存的头部**
`set_cache_settings` 操作会在 Cloudflare 评估缓存之前,从源响应中移除如 `Set-Cookie`、`ETag` 或 `Last-Modified` 的信息。
这是解决 `Set-Cookie-on-a-static-asset` 问题的修复。源框架通常将会话 Cookie 附加到每个响应中(用于负载均衡或其他目的),包括用户不希望与会话关联的资产的响应。在响应阶段去除 `Set-Cookie` 使这些资产再次可缓存,而无需要求源、负载均衡器或其他所有上游更改。
缓存响应规则也适用于那些根本不适合缓存的响应。所以当你对动态响应去除 Set-Cookie 时,这条规则会在对象是否存储时都会触发。这让你即使在响应不储存于缓存的情况下,也能够控制客户端看到的内容。你也可以去除 ETag 和 `Last-Modified`,当这些头部在源端配置错误并导致混乱时,这非常有用。这又伴随着一个权衡:去除 ETag 和 Last-Modified 就会启用 [**智能边缘重新验证**](https://blog.cloudflare.com/introducing-smart-edge-revalidation/) 对该响应。但如果缓存响应规则随后**添加**新的验证器,Cloudflare 不会为浏览器条件请求启用智能边缘重新验证。
所以,去除和修改头部的能力,即使在动态请求上,也是 Cloudflare 之前不存在的强大新模式,但如果你进行这些更改,仍然需要注意一些附加的配置。

2. **管理缓存标签**
`set_cache_tags` 允许你 **添加**、**移除** 或 **设置** 响应中用于 [**通过标签清除缓存**](https://developers.cloudflare.com/cache/how-to/purge-cache/purge-by-tags/) 的缓存标签。标签可以是静态的:

或者从响应头表达式计算得出:

这种第二种形式在 CDN 迁移过程中非常有用。如果你之前的 CDN 在响应中附加了类似 `Surrogate-Keys` 这样的头部来创建替代键,你可以在响应阶段直接将其转换为 Cloudflare 的 `Cache-Tag` 格式。
分割函数的第三个参数是限制:结果数组中的最大元素数可以在 1 到 128 之间。这个值应远高于每个响应的实际标签计数。值为 1 将返回整个头部作为一个单标签。一旦标签存在于响应中,[**通过标签清除缓存**](https://blog.cloudflare.com/instant-purge/) 就能正常工作(而又通常是在 [**150毫秒内,全球范围内**](https://blog.cloudflare.com/instant-purge/))。

3. **修改 Cache-Control 指令**
`set_cache_control` 是执行最多工作的操作。你可以设置或移除个别指令:
- 持续时间指令:`max-age`、`s-maxage`、`stale-if-error`、`stale-while-revalidate`
- 有限指令:`private`、`no-cache`(可选头名称限定符)
- 布尔指令:`no-store`、`no-transform`、`must-revalidate`、`proxy-revalidate`、`must-understand`、`public`、`immutable`

对于每个指令,你也可以设置 `cloudflare_only`:true,这往往会让人感到惊讶:当 `cloudflare_only` 为真时,该指令影响 Cloudflare 如何缓存响应,但发给浏览器的下游 Cache-Control 值保持不变。这是响应阶段的版本,类似于 `CDN-Cache-Control` 在源中的作用:在 Cloudflare 缓存该资产 24 小时,但告知浏览器其他内容。不同之处在于你现在可以在 Cloudflare 控制面板的规则表面上做到这一点,而无需请求源设置另一个头部。

## 值得借鉴的示例

以下是一些示例,我们认为可以帮助您展示缓存响应规则的强大。尝试它们,进行重组,并与社区其他人分享,以便您能够了解如何使用缓存规则和缓存响应规则实现强大的缓存自定义。更多示例可以在 [**文档**](https://developers.cloudflare.com/cache/how-to/cache-response-rules/create-api/#example-requests) 中找到。

### **去除静态资源扩展中的 Set-Cookie**
**为什么它有效**:导致“这应该是可缓存但不是的”的最常见原因是源上的会话中间件将 `Set-Cookie` 附加到**每个**响应。去除已知静态扩展的此头部可使这些响应在无需源更改的情况下变为可缓存。

**注意事项**:仅在 Cookie 在这些 URL 上不是语义上必要的资源类型上执行此操作(这很少见但可能)。

### **在 Cloudflare 中长时间缓存静态资产,在浏览器中缩短缓存**
**为什么它有效**:Cloudflare 将资产维持一个月并从缓存中提供它。浏览器看到 `max-age=86400` 并在一天后重新验证。您不必更改源,就可以解耦两个缓存生命周期。

**注意事项**:`immutable` 告诉浏览器即使是在显式刷新时也不进行重新验证。仅与版本化/哈希文件和文件名一起使用。

### **在已知静态路径上覆盖 no-cache**
**为什么它有效**:框架默认情况下通常将 `no-cache` 附加到每个响应。如果你知道 `/static/*` 是安全的,可以去除该指令并施加自己的 TTL(仅在 Cloudflare),而无需更改源或任何下游缓存看到的内容。

**注意事项**:要如实描述什么确实是静态的。如果 `/static/` 有时被用来提供用户特有的内容,则需收窄匹配(扩展、响应头信号、内容类型)。

### **在 CDN 迁移期间翻译缓存标签**
**为什么它有效**:许多 CDN 迁移的问题来自源工具发出的以另一厂商格式发出的缓存标签头部。不要请求源团队发布一个版本来添加 Cloudflare 的 `Cache-Tag`,在响应阶段翻译现有头部。Cloudflare 的通过标签清除缓存功能可立即开始工作。

**注意事项**:分割函数的第三个参数是限制(1-128),与结果数组的大小有关,而不是与分隔符有关。

## 如何使用缓存响应规则

**仪表盘**
1. 在 Cloudflare 控制面板中转到 **缓存** > **缓存规则**。
2. 选择“创建规则”,然后选择 **缓存响应规则**。
3. 选择名称和表达式。表达式构建器显示请求字段和响应字段。
4. 选择操作:**修改 cache-control 指令**、**修改缓存标签**或者**去除头部**。
5. 对于指令,当你希望更改仅适用于 Cloudflare 或者的资产的视图时,切换为 **Cloudflare 仅适用**。
6. 将其保存为草稿以进行迭代,或直接部署。

### **API**

在此阶段的规则的地址为:

有关如何使用缓存响应规则(包括 API 和 terraform 示例)的更多信息,请参见 [**文档**](https://developers.cloudflare.com/cache/how-to/cache-response-rules/create-api/)。

## 今天就使用缓存响应规则

缓存规则查看了请求。缓存响应规则查看了响应。这两者都为您提供了更多控制,以建立完美的 Cloudflare 缓存。它们目前在所有计划上都可用——请去 [**尝试它们**](http://dash.cloudflare.com/?to=/:account/:zone/caching/rules/response-rules/new)!

---

原文链接:[点击查看](https://blog.cloudflare.com/introducing-cache-response-rules/)

评论

暂无评论。