跳转到内容
搜索文档

调试

最后更新 查看 MarkdownAgent 设置

如果缓存行为不符合预期,Cf-Cache-Status 响应头是你首先要查看的地方。每个响应都会携带该头,其值会准确告诉你该请求发生了什么。

检查 Cf-Cache-Status

向同一 URL 发送两次请求并比较响应头:

curl -I https://my-worker.example.workers.dev/api/users/42
curl -I https://my-worker.example.workers.dev/api/users/42

将状态值与以下场景对照。

我的 Worker 在每次请求时都会运行

Cf-Cache-Status 不存在。请确认你的 wrangler 版本为 4.69.0 或更高,并且 wrangler.toml 或 wrangler.jsonc 中该 Worker 已设置 cache.enabled = true

Cf-Cache-Status 在每次请求时都是 MISSDYNAMICBYPASS。缓存未存储任何内容,或 bypass 规则被触发。

检查 Cache-Control 响应头。 响应必须携带使其可缓存的指令:

  • public, max-age=N — 在 Cloudflare 和浏览器中缓存 N 秒。

带有 Cache-Control: privateno-store 的响应不会被存储,Cf-Cache-StatusBYPASS

带有 Cache-Control: no-cache 的响应_会_被存储,但 Cloudflare 会将每次后续请求视为 stale,并在提供内容前向你的 Worker 发起校验。具体的 Cf-Cache-Status 取决于是否同时设置了 stale-while-revalidate

  • 仅使用 Cache-Control: no-cache 时,每次后续请求都会触发 inline revalidation。若 Worker 返回 304 Not ModifiedCf-Cache-StatusREVALIDATED(响应体来自缓存);若 Worker 返回新的 200,则为 EXPIRED(响应体被替换)。
  • 使用 Cache-Control: no-cache, stale-while-revalidate=N 时,缓存的响应体会立即提供,Worker 在后台运行。在 SWR 窗口内,Cf-Cache-StatusUPDATING

若你希望获得长期缓存命中,请改用 max-age。请参阅 no-cache 不是 bypass

如果响应完全没有 Cache-Control 响应头,行为取决于状态码:Workers Caching 会应用 RFC 9111 启发式 freshness,并按启发式 TTL 缓存默认可缓存的状态码 — 例如,200 缓存 2 小时,404 缓存 3 分钟。完整默认 TTL 表请参阅配置参考中的没有 Cache-Control 响应头的响应仍会被缓存。若不希望任何默认行为生效,请在响应上显式设置 Cache-Control

检查请求方法。 只有 GETHEAD 请求会被缓存。其他所有方法均为 BYPASS。同一 URL 的 GETHEAD 请求共享同一缓存条目 — 请参阅缓存键了解 Cloudflare 如何处理任一方法填充缓存。

检查自动 bypass 条件。 在以下情况下 Cloudflare 会 bypass 缓存:

  • 响应包含 Set-Cookie 响应头。
  • 请求包含 Authorization 响应头,除非响应显式设置了 Cache-Control: publicmust-revalidates-maxage

若 Worker 无条件设置 Set-Cookie(例如在每个响应上设置 session cookie),该响应永远不会被缓存。请从可缓存响应中移除 cookie,或将设置 cookie 与可缓存响应拆分到不同路由。

检查状态码。 Workers Caching 遵循 RFC 9111。默认不可缓存的状态码(例如 401403500)不会被存储,除非你显式用可缓存指令标记它们。

少数状态码即使带有显式 Cache-Control 也永远不会被缓存:

  • 520526 被视为 Cloudflare failsafe 响应,永远不会被存储。
  • Worker 返回的 206 Partial Content 不会被存储。Workers Caching 会通过从你的 Worker 获取完整响应体并从缓存条目中切片来处理 Range 请求 — 若 Worker 自行返回 206,该响应被视为不可缓存。请改为返回完整的 200。请参阅 Range 请求

我的 Worker 在首次请求后仍会运行

第一次请求时 Cf-Cache-StatusMISS,但后续请求仍为 MISS

缓存很可能被分区了。 缓存键包含请求路径、目标 entrypoint 以及调用的 ctx.props。对你来说看起来相同的两条请求,若上述任一因素不同,可能产生不同的缓存键。

常见原因:

  • 请求之间的 URL 路径或查询字符串不同(连尾部斜杠也有影响)。
  • 调用 Worker 为每次请求传入不同的 ctx.props — 例如不同的用户 ID。
  • 请求命中同一 Worker 的不同命名 entrypoint

Cloudflare 目前不暴露缓存键的组成,因此无法直接查看计算后的键。请改为逐项核对缓存键中列出的组件,确认两次请求的每一项都相同。

部署后缓存命中率下降

在默认配置下这是预期行为。默认情况下,Worker 版本是缓存键的一部分,因此每个新版本都从冷缓存开始,无法复用上一版本的缓存响应。部署后的首批请求为 miss,新版本的缓存逐渐填充后,命中率会恢复。

若你频繁部署且响应在部署之间很少变化,可启用 cache.cross_version_cache 以跨版本共享缓存响应,避免每次部署都重置缓存。代价是会影响缓存的变更不再立即生效 — 见下文。

部署后缓存仍提供旧内容

默认情况下部署会立即生效,因为 Worker 版本是缓存键的一部分,新版本从冷缓存开始。若仍看到来自旧版本的响应,说明已启用 cache.cross_version_cache,它会在版本间共享缓存条目。要在保持 cross_version_cache 开启的同时强制部署生效:

内容变更后缓存从不更新

若源数据已变更但请求仍返回 stale 内容:

  • 检查 TTL。 响应会在 max-age 秒内保持缓存。你看到的可能是仍在 freshness 窗口内的响应。
  • Purge 受影响的响应。 使用 ctx.cache.purge() 配合标签或路径前缀使特定条目失效。请参阅Purge 缓存
  • 在写入时添加标签。 若未设置 Cache-Tag 响应头,则无法按标签 purge。为缓存响应添加标签、部署,新条目写入后即可被 purge。

两个调用方收到彼此的缓存响应

若使用 ctx.props 承载按调用方的授权上下文,这不应发生。若发生了,以下之一为真:

  • 你使用未纳入缓存键的响应头或查询参数对调用方进行身份验证。将授权输入移入 ctx.props。请参阅使用 ctx.props 实现多租户安全
  • 你通过 service binding 调用时使用了特定于用户的查询参数,但该参数不存在。查询字符串是缓存键的一部分;请确保每个调用方的请求路径确实不同。

Cf-Cache-Status: UPDATING 持续出现

UPDATING 表示响应从 stale 缓存中提供,Worker 在后台运行以刷新它。使用 stale-while-revalidate 时这是预期行为。

UPDATING 出现频率超出预期:

  • 你的 max-age 短于请求到达频率。max-age 过期后到达的每个请求都会触发 revalidation。
  • 使用 max-age=0, stale-while-revalidate=<large> 时,每个请求都会触发 revalidation。这是「始终从缓存提供」的行为,而非「不运行 Worker」。请参阅选择 TTL 和 stale-while-revalidate 值

Cf-Cache-Status: UPDATING 从不出现

UPDATING 仅在以下全部条件成立时才会发出:

  • 存在缓存条目且已超出 freshness 窗口(stale)。
  • 响应携带 stale-while-revalidate=N,且请求在条目变 stale 后的 N 秒内到达。
  • 响应同时携带 s-maxagemust-revalidateproxy-revalidate

若任一条件不成立,stale 条目的请求会走 inline revalidation,产生 EXPIRED(Worker 返回新响应体)或 REVALIDATED(Worker 返回 304 Not Modified)。

UPDATING 不出现的常见原因:

  • 响应上没有 stale-while-revalidate 指令。 默认 SWR 窗口为 0,因此没有显式指令时,每个 stale 请求都会在前台 revalidate。
  • 存在 s-maxagemust-revalidateproxy-revalidate 根据 RFC 9111 §4.2.4,这些指令禁止提供 stale 内容,因此 Cloudflare 在存在任一指令时会禁用 stale-while-revalidate(以及 stale-if-error)。若希望 stale-serving 生效,请用 max-age 设置 edge freshness 窗口。
  • SWR 窗口已过期。 若响应使用 max-age=60, stale-while-revalidate=120,条目变 stale 后的 120 秒内你会看到 UPDATING。之后到达的请求会回退到 inline revalidation。

Cf-Cache-Status: STALE 意外出现

STALE 表示 Cloudflare 提供了先前缓存的响应,因为本应刷新它的请求上 Worker 出错了 — 例如 Worker 抛出异常、超时或返回 5xx 响应。这是 stale-if-error 行为。请参阅使用 stale-if-error 在出错时提供 stale 内容

若出现 STALE 但未预期到:

  • Worker 在缓存填充或 revalidation 时失败。Workers 可观测性仪表板中检查本应产生新响应的请求上的错误。客户端看到 stale 响应而非 5xx,掩盖了真实的故障。
  • 未显式设置 stale-if-error,且响应不包含 s-maxage/must-revalidate/proxy-revalidate 此时 Cloudflare 的默认行为是在 Worker 出错时无限期提供 stale 响应,只要缓存条目未被 purge。若希望错误快速暴露给客户端,请在 Cache-Control 中设置 stale-if-error=0。详情请参阅使用 stale-if-error 在出错时提供 stale 内容
  • 正在提供先前部署的版本。 若已部署修复但 STALE 仍持续出现,来自故障版本的缓存条目仍会在每次出错时被提供。Purge 受影响的条目,以强制从当前版本重新填充。

要在客户端可观测性中区分 STALE 与正常的 HIT,请与响应一并记录 Cf-Cache-StatusSTALE 是唯一表明 Worker 正在失败而客户端未察觉的信号。

响应超出大小限制

若响应过大无法缓存,Cloudflare 不会存储它。即使响应在其他方面看起来可缓存,每次请求的 Cf-Cache-Status 都会是 MISS

各套餐的响应大小限制请参阅可缓存大小限制。请注意,发布时所有 Workers Caching 响应均受 Free 套餐大小限制 — 详情请参阅响应大小

我需要更多可见性

发布时,主要的调试入口是 Cf-Cache-Status 响应头,以及 Workers 可观测性仪表板中每次调用的缓存命中信息。

这篇文档对您有帮助吗?