HTML不能加contenthash后缀,因其是入口文档,改名会导致路径失效、SEO断链、PWA错乱;必须用no-cache+ETag协商缓存,而JS/CSS等静态资源才应加哈希并配immutable强缓存。

HTML 本身不能加 contenthash 后缀
给 index.html 改成 index.a1b2c3.html 是典型误操作。它不是静态资源,而是每次发布都可能变的入口文档——改名会导致所有相对路径(如 ./main.js)失效、SEO 断链、PWA 的 manifest.json 和 service-worker.js 中的 precache 列表全错乱。Webpack/Vite 默认不给 HTML 加哈希,就是出于这个工程现实。
更关键的是:即使你硬编码了 <script src="app.d41d8c.js"></script>,只要用户本地还缓存着旧版 index.html,浏览器就永远看不到这个新 URL —— 缓存链条断在第一环。
所以别折腾 HTML 文件名哈希,重点转向响应头控制和静态资源指纹。
HTML 必须用 no-cache + ETag 协商缓存
正确做法是让服务器对 HTML 返回协商缓存头,既避免强缓存导致页面陈旧,又不浪费带宽重传完整文件。
立即学习“前端免费学习笔记(深入)”;
Nginx 配置示例:
location = /index.html {
add_header Cache-Control "no-cache, must-revalidate";
add_header ETag "";
expires epoch;
}no-cache 不等于“不缓存”,而是强制每次发条件请求;ETag 由 Nginx 基于文件内容自动生成(推荐用 md5),比 Last-Modified 更可靠。
- 验证方式:DevTools → Network → 刷新 → 看
index.html请求的 Response Headers 是否含ETag,Status 是否出现304 Not Modified - 不要用
max-age=0替代 —— 它语义模糊,部分代理行为不一致;no-cache是明确走协商流程的首选 - 绝对禁用
public, max-age=31536000给 HTML,哪怕你用了构建哈希,入口仍是动态路由或 SSR 入口
JS/CSS 等静态资源必须加 contenthash 并配 immutable
真正要加哈希指纹的是 .js、.css、.woff2、.png 这类内容稳定、体积大、复用率高的资源。
Webpack 示例配置:
output: {
filename: "[name].[contenthash:8].js",
chunkFilename: "[name].[contenthash:8].js"
}Vite 默认开启 build.rollupOptions.output.entryFileNames 带 hash,无需额外配置。
Nginx 强缓存策略:
location ~* \.(js|css|woff2|png|jpg|gif)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}immutable 很关键:它告诉 Chrome 等现代浏览器“这个 URL 永远不会变内容”,后续访问跳过 If-None-Match 校验,省一次往返。
- 没加哈希就配
immutable是危险操作 —— 内容变了但 URL 不变,用户永远拿不到新版本 - CDN 或代理层若不支持
immutable,会 fallback 到ETag或Last-Modified,所以仍需确保服务端启用了etag on - 图片若来自 CMS 后台上传,无法自动加哈希,就得靠
ETag协商缓存,而非强缓存
meta http-equiv="Cache-Control" 在 HTML 中完全无效
你在 <head> 里写 <meta http-equiv="Cache-Control" content="no-cache">,DevTools 可能显示 header,但 Chrome/Firefox/Edge 实际都不认。这不是 bug,是规范明确不支持。
这个标签只在极个别 WebView 或旧版 Safari 中有降级行为,不能当作真实缓存控制手段。
真正起效的只有 HTTP 响应头:由 Nginx/Apache、Node.js 后端、或托管平台(如 Vercel 的 headers 配置)注入。
顺带一提:<meta> 对 <link> 和 <script> 引用的外部资源也基本无效 —— 浏览器按各自 URL 单独发起请求,根本不看 HTML 里的 meta。
最易被忽略的点是:HTML 的缓存策略和它引用的资源策略必须解耦。HTML 要“每次验证”,而 JS/CSS 要“永久可信”——这种不对称设计才是现代前端缓存的底层逻辑。一旦混淆两者角色,更新故障就必然发生。



















