index.html 绝对不能配 contenthash 后缀,因其是浏览器固定请求的入口路径,改名会导致路由、CDN、PWA 等多处失效;正确策略是 Cache-Control: no-cache + ETag 协商缓存。

HTML 文件本身不能加 contenthash 后缀实现指纹缓存——它不是静态资源,而是每次发布都可能变的入口文档。强行改名会导致路径失效、SEO 断链、PWA 错乱,且根本解决不了“用户拿不到最新 HTML 就加载不到新 JS”的核心问题。
为什么 index.html 绝对不能配 contenthash 后缀
Webpack/Vite 默认不给 HTML 加哈希,不是遗漏,是刻意为之:
-
index.html是浏览器固定请求的入口路径,改成index.a1b2c3.html就必须同步改 Nginx 路由、CDN 回源规则、manifest.json、service-worker.js的 precache 列表——维护成本爆炸 - HTML 内容频繁变动(标题、meta、内联脚本、动态
scriptsrc),但它的真正作用是“调度器”,不是被缓存的对象 - 即使你把
<script src="app.d41d8c.js"></script>写死在 HTML 里,只要 HTML 被强缓存住,浏览器就永远看不到这个新 URL —— 缓存链条断在第一环
Cache-Control: no-cache + ETag 才是 HTML 的正确缓存策略
目标不是“不缓存”,而是“每次验证后再用”:既避免陈旧页面,又不重复传整个 HTML 文件。
- Nginx 配置示例中,
add_header Cache-Control "no-cache, must-revalidate"强制发起条件请求;add_header ETag ""让 Nginx 基于文件内容自动生成 ETag(推荐 md5) -
no-cache不等于禁用缓存,它只是跳过强缓存阶段,直接走协商缓存;相比Last-Modified,ETag更可靠,能精准识别内容变更 - 验证方式:DevTools → Network → 刷新页面 → 看
index.html请求的 Response Headers 是否含ETag,Status 是否为304 Not Modified
JS/CSS 等静态资源才该用 contenthash + immutable
这些文件体积大、复用率高、内容稳定,适合构建时生成唯一哈希,并配强缓存头。
立即学习“前端免费学习笔记(深入)”;
- Webpack 中设
output.filename: "[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很关键:它告诉浏览器“这个 URL 永远不会变内容”,后续访问跳过If-None-Match校验,省一次网络往返
最容易被忽略的一点:HTML 的缓存行为完全由服务端响应头控制,<meta http-equiv="Cache-Control"> 在现代浏览器中被忽略;而前端构建工具生成的哈希,只有配合服务端正确的 Cache-Control 和 ETag 设置,才能形成闭环。



















