静态站的缓存头:带哈希的永久,HTML 一律不缓存
缓存策略只取决于文件名是否随内容变化,与文件大小无关。HTML 长缓存会让用户拿到旧入口、指向已删除的旧 chunk,是静态站最常见的线上白屏。
静态站上线之后最先暴露的问题不是速度,而是部署完之后页面白屏。原因几乎总是同一个:HTML 被缓存了,但它引用的资源文件名已经变了。
判断依据只有一条
「这个文件名会随内容变化吗?」会,就可以永久缓存;不会,就必须每次校验。跟文件大小、访问频率都无关。
构建产物分三类:
| 路径 | 文件名 | 缓存策略 |
|---|---|---|
/_astro/* |
带内容哈希 | max-age=31536000, immutable |
*.html |
固定 | no-cache |
/pagefind/* |
混合 | max-age=3600 |
为什么 HTML 不能长缓存
构建是原子的:一次 npm run build 会输出新的哈希文件名并删掉旧的。index.html 是唯一入口,如果它被浏览器缓存一年,用户打开的是上一次部署的 HTML,里面写着的 /_astro/index.abc123.js 在新部署里已经不存在 —— 结构和样式能出来,脚本 404,交互全失效。
no-cache 不是「不缓存」,而是「每次带 ETag 回来问一次」。命中时服务器回 304,正文不重传,成本是一个往返,换来的是永远不会引用到已删除的哈希。
location ~* ^/_astro/ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
location ~* \.html$ {
add_header Cache-Control "no-cache";
}
两个容易漏的地方
- Pagefind 的索引目录:
pagefind.js不带哈希,其余分片带。统一给一小时,既能跟上重建,也不至于每次搜索都重下几 MB。 sw.js/ manifest 之类约定俗成的入口:本站不做 PWA,所以没有这一类;如果做了,它们和 HTML 同级 —— 文件名不变,就不能长缓存。
别问「这个文件大不大」,问「改内容之后文件名会不会变」。

评论
…