KernelRanch
返回文章列表

缓存规则:把哪些请求留在边缘

2026-11-10 #Cloudflare

读完这篇你能做到:给自己的站点设计一套缓存策略,让静态资源在边缘长期驻留、页面按需短缓存、接口与后台完全不缓存,并且能用响应头判断某次请求到底命中了没有。

缓存做对了,回源次数和首字节时间会一起下降;做错了,用户看到的是改了没生效的旧页面,排查起来比性能问题更烦。这篇的顺序是先看默认行为,再设计规则,最后验证与清除。

1. 默认行为

Cloudflare 默认只缓存一部分静态扩展名(CSS、JS、图片、字体、音视频等),HTML 页面默认不进缓存。缓存键默认是主机名加路径加查询串。

这个默认值对纯静态站偏保守:每个页面请求都会回源,Pages 的回源很快,但仍有往返。想让 HTML 也进边缘,得自己加规则。

另一个默认值来自源站的响应头。源站给了 Cache-Control: max-age=...,边缘按它算 TTL;源站什么都没给,边缘用启发式缓存,行为不好预测。所以规则之外,源站头也要写清楚。

2. 按路径分四类

路径缓存资格Edge TTLBrowser TTL
/assets/*、/img/*缓存1 年1 年
/*.html、/缓存10 分钟5 分钟
/api/*绕过不缓存不缓存
/admin/*绕过不缓存不缓存

静态资源带内容哈希时才能给 1 年。immutable 的意思是"这一年里别来问我",文件名不变就永远拿不到新版本。固定文件名配长 TTL 会在改图后出问题,这一点在 73-image-optimization.md 里讲过。

HTML 用短 Edge TTL 是折中。10 分钟意味着发布后最多 10 分钟旧页面消失,访问量大的站点这段时间里绝大多数请求仍然命中边缘。要求发布即生效的站点,把 HTML 设成绕过缓存,成本是每次都回源。

接口和后台直接绕过。带登录态的响应一旦被缓存并被别人拿到,是安全事故而不是性能问题。

3. 在控制台建规则

位置在域名详情 → Caching → Cache Rules → Create rule。每条规则三部分:匹配表达式、缓存资格、TTL 设置。

静态资源那条:

(http.request.uri.path matches "^/(assets|img)/")

Cache eligibility: Eligible for cache
Edge TTL: Ignore cache-control header and use this TTL — 1 year
Browser TTL: Override origin — 1 year

页面那条用扩展名与根路径匹配:

(http.request.uri.path eq "/" or http.request.uri.path contains ".html")

Edge TTL: 10 minutes
Browser TTL: 5 minutes

接口与后台合起来一条绕过规则,表达式用 startsWith 更省事:

(http.request.uri.path starts_with "/api/" or http.request.uri.path starts_with "/admin/")

Cache eligibility: Bypass cache

命中顺序按规则列表从上到下,前面命中就停。把绕过规则放在最上面,可以避免后续规则误伤。

4. 源站头与边缘规则的分工

两层都能设 TTL,容易打架。约定一条界线会清爽很多:

源站负责语义。HTML 页面给 Cache-Control: public, max-age=0, must-revalidate,表达"内容会变,用之前确认一下"。带哈希的静态资源给 max-age=31536000, immutable。

边缘负责兜底与放大。源站头不完整时,用 Cache Rules 覆盖。

Pages 项目里源站头写在 _headers 文件,随产物一起上传。免费档限制是 100 条规则、单条 2,000 字符,够常规站点用。

/assets/*
  Cache-Control: public, max-age=31536000, immutable

/*
  X-Content-Type-Options: nosniff

5. 验证命中

改完规则要确认生效,不能只看控制台的规则列表。用 curl 看响应头:

curl -sI https://example.com/assets/app.a1b2c3.js | grep -i -E 'cf-cache-status|age|cache-control'

cf-cache-status 的几个取值含义:

值含义
HIT命中边缘缓存
MISS未命中,本次回源并写入缓存
DYNAMIC按规则不缓存
BYPASS规则或请求头要求绕过
EXPIRED有缓存但已过期,重新回源

同一个 URL 连请求两次,第一次 MISS 第二次 HIT,说明规则在起作用。两次都是 MISS,检查是否带了 Set-Cookie、Cache-Control: no-store,或者请求方法不是 GET。

age 头显示这份缓存已经存在多少秒,用来判断 TTL 是否符合预期。

6. 改完不生效怎么办

先确认规则顺序。后面的规则不会覆盖前面已经命中的。

再清除缓存。单 URL 清除在 Caching → Configuration → Purge,按 URL 精确清除,秒级生效。整站清除影响面大,非必要不用。

Dev Mode 可以临时让所有请求绕过缓存,持续三小时后自动关闭。调试期间打开它,避免一边改一边被旧缓存干扰。

如果清除了还是不生效,检查浏览器缓存。Browser TTL 设成 1 年的资源,在用户端也留了一年,边缘清了不代表浏览器清了。

常见问题

为什么 HTML 没被缓存。

默认扩展名列表里没有 HTML。要么加一条显式的 Cache Rule,要么在源站头里给 HTML 一个 s-maxage。两者选一个,别同时用。

免费档能建多少条规则。

Cache Rules 在免费档可用,规则条数有上限;旧的 Page Rules 免费档是 3 条。新项目直接用 Cache Rules,表达能力和可读性都更好。

缓存了带 cookie 的响应怎么办。

按路径绕过,或者在规则里加"存在 Set-Cookie 时不缓存"的条件。更稳的做法是让需要登录的路径全部走绕过规则,不给缓存层判断的机会。

小结

缓存规则的骨架是分类:长期不变的静态资源、会变的页面、不能缓存的接口和后台。三类各自一条规则,顺序上绕过在前。

规则只是声明,验证要靠响应头。cf-cache-status 从 MISS 变 HIT 才算真的生效。剩下的事是清理:单 URL 清除处理个别文件,Dev Mode 处理调试期,整站清除尽量少用。

响应头在 Pages 项目里写在 _headers,随构建产物一起上传,产物目录的关系见 67-pages-getting-started.md;重定向与缓存的交互见 75-redirects-bulk.md。

数据来源与检索时间

检索时间 2026-11-10。

来源URL对应数据
Cache Rules 文档https://developers.cloudflare.com/cache/how-to/cache-rules/规则组成、缓存资格与 TTL 选项、按表达式匹配
缓存响应头说明https://developers.cloudflare.com/cache/concepts/cache-responses/cf-cache-status 各取值含义
Pages Limitshttps://developers.cloudflare.com/pages/platform/limits/_headers 最多 100 条规则、单条 2,000 字符
清除缓存https://developers.cloudflare.com/cache/how-to/purge-cache/单 URL 清除与整站清除、Dev Mode 的用途

核验说明

  • 文档部分:_headers 的条数与单条长度限制来自 2026-11-10 抓取的 Pages Limits 页面;cf-cache-status 取值与规则选项依据 Cache 文档。
  • 未执行:本机 Token 没有 Zone 权限,没有创建过任何 Cache Rule,也没有执行过清除缓存或开启 Dev Mode。控制台步骤全部依据文档描述。
  • 未执行:curl -sI 的验证命令没有对真实站点运行,示例输出未贴出真实结果。
  • 未核实:Cache Rules 在免费档的具体条数上限,正文只说"有上限"没有给数字;Page Rules 免费 3 条为长期公开的额度,未在控制台核对。
  • 本地构建验证:无。