文件指纹通过在构建时为每个静态资源生成基于内容的哈希并嵌入文件名(如app.7f9a2c1d.js),实现内容变更即URL变更,从而强制浏览器和CDN加载新版本;必须用contenthash而非hash或chunkhash,因其严格按单个文件内容生成哈希,确保未修改资源缓存完全复用。

资源缓存失效通过文件指纹实现版本更新,核心是让每个静态资源(JS/CSS/图片等)的 URL 变得“内容敏感”——内容一变,URL 就变,浏览器和 CDN 自然无法命中旧缓存,必须拉取新文件。
文件指纹是怎么工作的
文件指纹是在构建时,根据文件内容生成一段哈希值,并嵌入到文件名中。例如:
- 原始文件:
app.js - 加指纹后:
app.7f9a2c1d.js(哈希基于内容计算)
只要源码哪怕改一个字符,哈希值就会完全不同,输出文件名随之改变。浏览器看到新 URL,就当作全新资源处理,彻底绕过旧缓存。
为什么必须用 contenthash 而不是 hash 或 chunkhash
Webpack 提供多种哈希方式,但只有 contenthash 能精准绑定单个文件内容:
- hash:整个构建生成一个哈希,任意文件改动都会导致所有输出文件名变更 → 连带刷新未修改资源,浪费缓存
- chunkhash:按代码块(chunk)生成哈希,适合多入口场景,但 CSS 和 JS 若共用 chunk,仍可能互相影响
- contenthash:严格按文件内容生成哈希,CSS 改了只影响 CSS 文件名,JS 改了只影响 JS 文件名 → 缓存复用率最高
推荐配置(Vite 或 Webpack):
Webpack:output: { filename: '[name].[contenthash:8].js', chunkFilename: '[name].[contenthash:8].chunk.js' }Vite:
build: { rollupOptions: { output: { entryFileNames: 'assets/[name].[hash].js' } } }(Vite 默认已启用 content-based hash,无需额外配置)配套的缓存策略要跟上
光有指纹还不够,服务端和 HTTP 头需配合长期缓存:
- Nginx 中对带指纹的静态资源设置强缓存:
location ~* \.(js|css|png|jpg|gif|woff2)$ { expires 1y; add_header Cache-Control "public, immutable"; } - immutable 是关键:告诉浏览器“这个 URL 永远不会变内容”,可跳过后续验证请求(如 If-None-Match),大幅提升重复访问性能
- HTML 文件则相反:应禁用强缓存,用
Cache-Control: no-cache或短时效(如max-age=300),确保能及时加载含新资源链接的 HTML
上线后如何验证是否生效
部署后快速检查三处:
- 浏览器开发者工具 → Network 标签页 → 刷新页面 → 查看 JS/CSS 请求的 Response Headers 中是否有
Cache-Control: public, immutable和Expires时间为 1 年后 - 对比前后两次构建产物目录,确认文件名中的哈希段确实变化(如从
main.a1b2c3.js变为main.d4e5f6.js) - 在浏览器中直接访问旧文件 URL(如复制上次部署的 JS 地址),应返回 404 —— 表明旧指纹资源已被移除,CDN 和浏览器均无法再加载它


















