应采用文件名哈希策略实现静态资源版本控制:构建时生成带contenthash的唯一文件名(如main.a1b2c3d4.js),HTML通过构建插件注入路径,CDN回源配置需保留哈希、源站服务器允许该路径访问,服务端对哈希资源返回Cache-Control: public, max-age=31536000, immutable,HTML则禁用长期缓存,并协调Service Worker避免缓存冲突。

CDN 缓存失效后如何强制用户加载新版静态资源
CDN 不会自动感知你本地打包出的新 main.js 或 styles.css,它只认 URL。如果文件路径不变(比如始终是 /static/js/main.js),哪怕你已上传新内容,CDN 仍可能返回旧缓存。解决办法不是清 CDN 缓存——那不可控、有延迟、还可能误伤其他资源——而是让新版本资源拥有唯一 URL。
- 构建时在文件名中嵌入哈希值,例如生成
main.a1b2c3d4.js而非main.js,Webpack/Vite 默认开启contenthash即可 - HTML 中通过构建插件注入正确路径(如 Vite 的
import.meta.env.BASE_URL,Webpack 的HtmlWebpackPlugin自动替换) - 避免手动拼接路径或写死
src="/static/js/main.js",否则哈希更新后 HTML 仍引用旧名 - 注意:CSS 中的字体、图片等相对路径若未被构建工具处理,也可能绕过哈希机制,需确认是否走
url()内联或被asset规则捕获
CDN 回源配置不当导致版本文件 404
当请求 /static/js/main.a1b2c3d4.js 时,CDN 若回源到源站却只找 /static/js/main.js,就会 404。这不是前端代码问题,而是 CDN 源站映射规则没对齐。
- 检查 CDN 控制台「回源路径重写」设置:确保不把带哈希的文件名截断或正则替换掉(例如错误地将
\.([a-f0-9]{8})\.js$替换为空) - 源站 Web 服务器(Nginx/Apache)要允许点号和字母数字组合的文件名被直接读取,禁止因安全规则拦截
.a1b2c3d4.js类路径 - 上线前用
curl -I https://cdn.example.com/static/js/main.a1b2c3d4.js验证状态码,别只测 HTML
Cache-Control 头与 CDN 缓存策略冲突
即使文件名带哈希,如果响应头里写了 Cache-Control: max-age=31536000,CDN 会缓存一年;但若你中途紧急回滚,CDN 不会主动刷新,用户就卡在旧版逻辑里。
- 对哈希文件(JS/CSS/字体/图片),服务端应返回强缓存头:
Cache-Control: public, max-age=31536000, immutable——immutable告诉浏览器“这资源永不变”,可跳过条件请求 - 对 HTML 文件,必须禁用长期缓存:
Cache-Control: no-cache或max-age=0,否则用户永远看不到新 JS 的入口 - CDN 控制台中,不要覆盖源站的
Cache-Control头(尤其避免全局设成 1 小时),优先信任源站策略
Service Worker 和 CDN 版本控制打架
如果你同时用了 Service Worker(比如 Workbox),它可能把旧版哈希文件缓存在本地,即使 CDN 已返回新版 HTML 和新脚本 URL,SW 仍拦截请求并返回旧缓存。
- Workbox 默认缓存策略对
/*.js是 Stale-While-Revalidate,需显式排除哈希文件或改用 NetworkFirst - 更稳妥的做法:在 SW 更新逻辑中监听
waiting状态,并提示用户刷新,或调用skipWaiting()+clients.claim()主动激活 - 开发阶段用 Chrome 的 Application → Service Workers → 「Update on reload」勾选,避免本地调试时被 SW 锁死旧版本
哈希文件名只是起点,CDN 配置、源站响应头、客户端缓存层(浏览器 + SW)三者必须同步对齐,漏掉任何一环,版本控制就形同虚设。

















