html 应进 cdn 缓存,但必须设短 ttl(5–30 分钟)或协商缓存(cache-control: no-cache 或 max-age=0, must-revalidate),配合 etag 校验;静态资源需文件名含哈希且配 public, max-age=31536000, immutable。

HTML 文件该不该进 CDN 缓存?
应该进,但必须设短缓存或协商缓存——Cache-Control: no-cache 或 max-age=0, must-revalidate 是底线。CDN 节点缓存 HTML 能减少源站回源压力,但若缓存太久,用户会拿到旧版 index.html,导致引用的 JS/CSS 哈希路径 404、页面白屏或功能异常。
常见错误现象:
- 上线新包后部分用户点击按钮无反应,查 Network 发现加载的是
app.oldhash.js404 - CDN 控制台显示 HTML 缓存命中率 99%,但实际内容已过期 2 小时
关键点:
- CDN 对 HTML 的缓存 TTL 建议设为 5–30 分钟(动态页)或 1 小时(静态首页),而非“永不过期”
- 比 TTL 更可靠的是开启 ETag + 协商缓存:CDN 节点收到请求后,带
If-None-Match回源校验,源站返回304 Not Modified就复用本地副本 - 别依赖
Expires头——客户端时间可能不准,优先用Cache-Control
JS/CSS/图片等静态资源怎么配 CDN 缓存才不翻车?
必须满足两个条件:文件名含内容哈希 + Cache-Control: public, max-age=31536000, immutable。缺一不可。
构建工具输出示例(Webpack/Vite):
main.ea7f2d.js vendor.8c3b1a.css logo.f9d2e4.png
对应 CDN 缓存配置(Nginx 或 CDN 控制台):
- 匹配路径
.*\.(js|css|png|jpg|woff2)$ - 设置响应头:
Cache-Control: public, max-age=31536000, immutable - 启用
ETag on(备用校验机制)
容易踩的坑:
- 只加了
max-age=31536000,但文件名没哈希 → 浏览器永远认同一个 URL,改了内容也不更新 - 用了
immutable却没确保文件名哈希稳定(比如 Vite 中build.rollupOptions.output.entryFileNames没配[name].[hash])→ CDN 可能缓存错版本 - 把字体文件(
.woff2)漏在缓存规则外,导致每次加载都走回源
如何验证 CDN 缓存是否生效且策略正确?
别信控制台数字,直接看浏览器 DevTools 的 Network 面板里每个请求的真实响应头和状态码。
分三类查:
-
index.html请求:Response Headers 里必须有Cache-Control: no-cache或max-age=0, must-revalidate;Status 应为304 Not Modified(协商命中)或200 OK(首次/更新);绝不能是200 OK (from disk cache)(说明强缓存意外生效) -
main.xxxx.js请求:Response Headers 里应有Cache-Control: public, max-age=31536000;Status 为200 OK (from memory cache)或(from disk cache)才算成功长期缓存 - 检查 CDN 域名是否真正生效:Request URL 必须是
https://static.example.com/js/main.xxxx.js,而不是https://example.com/js/main.xxxx.js—— 后者说明构建时publicPath或base没配对
注意:如果开了 Service Worker,它可能劫持请求并掩盖真实 CDN 行为,测试前建议在 Application → Service Workers 里点击 “Unregister” 临时禁用。
HTML 入口文件更新后,如何避免 JS/CSS 缓存错配?
核心矛盾在于:HTML 要快(靠 CDN 缓存),但又要准(不能卡在旧版本);而 JS/CSS 要稳(靠长期缓存),但又要新(哈希变了就得换)。解法不是让 HTML 不缓存,而是让它“缓存但可验证”。
实操要点:
- 确保源站(Nginx/Express)对
/index.html返回带 ETag 的响应:Nginx 加etag on;,且不覆盖掉;Express 用res.set('ETag', crypto.createHash('md5').update(htmlContent).digest('hex'))手动生成 - CDN 配置里开启“源站校验”或“协商缓存透传”,确保
If-None-Match请求能抵达源站,而不是被 CDN 自己判 304 - 发布流程中,HTML 文件必须和它引用的 JS/CSS 同步上线——不能先推 JS 包再推 HTML,否则中间窗口期用户会加载失败
- 如果用 SSR 或动态路由(如 Next.js / Nuxt),HTML 本身无法静态化,那就必须关掉 CDN 对 HTML 的强缓存,只保留
max-age=60级别的短缓存,并依赖Last-Modified校验
最易被忽略的一点:CDN 缓存策略和构建产物哈希是绑定关系。你改了 Webpack 的 output.filename 模板却忘了同步更新 CDN 缓存规则正则,结果新生成的 chunk 文件被当成未匹配资源,走了默认的短缓存——表面看着正常,实则浪费了长期缓存红利。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











