Cloudflare Workers 的 _headers 缓存规则边界
把博客搬到 Cloudflare Workers 静态资产后,static/_headers 里写了一条自认为标准的规则:
/*.(css|js|woff2)
Cache-Control: public, max-age=31536000, immutable
它从来没有生效过。
一、_headers 只支持 * 和 :placeholder
CF 的 _headers 模式不支持 (css|js|woff2) 这种正则分组,而且是静默失效:不报错、不警告、不匹配任何 URL。同一份文件里的 /*(安全头)和 /*.md(charset)都正常,说明文件被读取了、前缀也没写错,唯一变量是模式语法。官方示例里只有 /static/* 这类纯通配写法。
判别任何 header 规则是否生效,第一条命令:
curl -sI https://tianheg.co/css/main.<hash>.css | grep -i '^cache-control'
# 返回 public, max-age=0, must-revalidate → 规则没生效,这是 Workers 静态资产的默认值
能用的粒度只有目录或前缀,* 贪婪跨 /:
/css/*
Cache-Control: public, max-age=31536000, immutable
二、部署即删:旧 hash 文件立刻 404
更反直觉的一条:CF Workers 每次部署只保留当前版本那一份资产,上一次部署的 hash 文件立刻消失。
Hugo 的 fingerprint 是内容 sha256,所以重建旧 commit 就能拿到当时线上真实用过的文件名:
cd ~/projects/blog
git worktree add --detach /tmp/blog-old <旧commit>
ln -s ~/projects/blog/node_modules /tmp/blog-old/node_modules
cd /tmp/blog-old && PATH="$PWD/node_modules/.bin:$PATH" hugo --gc --minify -d /tmp/blog-oldout
ls /tmp/blog-oldout/css # ← 当时线上用过的文件名
curl -s -o /dev/null -w '%{http_code}\n' https://tianheg.co/css/main.<旧hash>.css
curl -sI https://tianheg.co/css/main.<旧hash>.css | grep -i content-type
cd ~/projects/blog && git worktree remove --force /tmp/blog-old
实测结果:旧 main.4324f2c0….css、旧 table.min.29f145ea….css → 404 + content-type: text/html;当前 main.91ab9cf….css → 200 + text/css。
前置自检很重要:先用当前 HEAD 构建一次,产出必须与线上现用 hash 逐字一致,才证明「本地构建等于 CI 构建」,否则 worktree 拿到的名字不能代表线上。
404 返回的是 404 页面(HTML)。浏览器对 <link rel=stylesheet> 和 <script> 都做严格 MIME 检查,拿到 text/html 直接拒绝应用或执行(DevTools 报 MIME type 错误)。症状不是「样式过期」,是「样式加载失败、页面裸奔」。
三、所以不要给 /css/* 加长缓存
_headers 按路径匹配,与状态码无关。把 /css/* 标记成 immutable,那条 404 响应也会被打上一年的 immutable —— CF 边缘和浏览器都会记住它。一次「部署瞬间的版本错配」(用户手上的 HTML 是旧版、资源请求落在新部署上)就能把那个用户锁死一年,浏览器侧 purge 无解。
收益只有省一次条件请求,而 CF 边缘本来就对 /css/* 返回 HIT。
保留 Workers 默认的 public, max-age=0, must-revalidate 加 etag:它恰好最契合「部署即删旧资产」的语义。
四、两条纪律
- 固定名资源一律不能长缓存:字体(
/fonts/Satoshi-Variable.woff2)、Pagefind 输出(/pagefind/pagefind.js、pagefind-ui.css)、static/里直接复制的手写 JS 和 CSS —— 升级后文件名不变,长缓存等于让老用户拿一年旧文件 - 别在外部系统里硬引用带 hash 的 URL(RSS 模板、别的站点嵌你的 CSS、邮件模板)—— 下次部署必 404