HTML文件必须短缓存或禁用强缓存,JS/CSS/图片等静态资源须长缓存+内容哈希+immutable;混用会导致白屏、文案错乱、功能失效。

静态网页的缓存管理不是“设个头就完事”,而是要分角色处理:HTML 文件必须短缓存或禁用强缓存,而 JS/CSS/图片等静态资源必须长缓存 + 内容哈希 + immutable。混用会导致页面白屏、文案错乱、功能失效。
为什么 index.html 不能加 max-age=1年
HTML 是入口文件,哪怕内容看似静态,实际常承载动态逻辑(如多语言切换、用户状态注入、SPA 路由入口)。一旦它被强缓存,浏览器下次访问直接复用旧 HTML,但其中引用的 main.js 可能已是新版本(或旧版本),造成 JS/CSS 版本错配。
- 现象:页面加载后按钮无响应、中文页显示英文文案、
document.getElementById找不到元素 - 根本原因:浏览器没发请求,服务端完全没机会返回新 HTML
- 正确做法:服务端对
/index.html返回Cache-Control: no-cache, must-revalidate, max-age=0,强制每次验证 - Nginx 示例:
location = /index.html { add_header Cache-Control "no-cache, must-revalidate"; expires epoch; }
JS/CSS/图片必须用 contenthash + immutable
只设 max-age=31536000 不够——URL 不变,内容变了,浏览器照样用旧缓存。必须让文件名本身携带内容指纹,再配合 immutable 跳过协商请求。
- Webpack/Vite 构建时启用
contenthash,输出类似main.7f8a2c.js、locales/zh-CN.b3e91d.json - Nginx 配置匹配扩展名并加头:
location ~* \.(js|css|json|woff2|png|jpg|gif)$ { expires 1y; add_header Cache-Control "public, immutable"; } - 漏掉
immutable:每次访问仍会发If-None-Match请求,多一次 RTT - 加了
immutable却没哈希:缓存彻底锁死,改了代码用户永远看不到
CDN 和本地开发环境的缓存陷阱
CDN 默认可能自动缓存所有 .html,而本地开发(如 Webpack Dev Server)默认返回 Cache-Control: no-store。两者行为不一致,极易在上线后暴露问题。
立即学习“前端免费学习笔记(深入)”;
- Cloudflare/Vercel 等 CDN 必须关闭「自动 HTML 缓存」,显式配置规则匹配
/**/*.html并设为max-age=0 - Webpack Dev Server 若手动加了缓存头,务必清空浏览器磁盘缓存,否则热更新失效(改了代码但页面没变)
- F5 刷新会跳过强缓存但保留协商缓存,所以即使配了 1 年缓存,F5 后仍可能出现一次
304——这不是配置错误,是规范行为
最易被忽略的一点:所有缓存策略都依赖服务端真实响应头,<meta http-equiv="Cache-Control"> 在现代浏览器中完全无效;验证必须看 Network 面板的响应头字段,而不是 HTML 源码里写了什么。



















