核心是用哈希指纹生成带版本的文件名,使url随内容变化,浏览器自动失效旧缓存;nginx无需主动清理,只需对含哈希的静态资源配置长期强缓存(max-age=31536000, immutable),html则依赖etag协商缓存。

核心是让文件名随内容变化,浏览器自然放弃旧缓存——版本号不是“防失效”,而是让缓存“自动失效”。关键不在Nginx怎么清,而在于它根本不用清。
用哈希指纹生成带版本的文件名
构建阶段就让资源路径自带内容标识,比如 Webpack/Vite 输出 app.a1b2c3.js、style.f456.css。只要内容变,哈希就变,URL 就变,浏览器会当作全新资源请求,旧缓存完全无关。
- HTML 中必须引用新路径:
<script src="/js/app.a1b2c3.js"></script> - 确保构建工具启用
contenthash(推荐)或fullhash,避免仅用hash导致不同文件哈希冲突 - 字体、图片等二进制资源同样适用,如
icon.789def.svg、logo.012abc.png
Nginx 配置匹配哈希特征,配长期强缓存
有了带哈希的文件名,就可以放心设最长缓存,且加 immutable 省去验证开销:
- 用正则精准匹配含哈希的静态资源:
location ~* "\.[a-f0-9]{8,}\.(js|css|png|jpg|svg|woff2)$" - 响应头统一加:
add_header Cache-Control "public, max-age=31536000, immutable" always; -
always参数确保 304 或错误响应也带上该头,避免 CDN 或代理误判
HTML 必须走协商缓存,不依赖文件名变更
HTML 是入口,无法靠改名驱动更新,必须每次确认是否变化:
- 禁用强缓存:
add_header Cache-Control "no-cache, must-revalidate"; - 启用
ETag(默认开启)或Last-Modified,让浏览器发If-None-Match请求 - Nginx 收到匹配的 ETag 会直接返回 304,不传正文,省带宽又保实时性
避免“伪版本号”踩坑
只在 URL 后加 ?v=1.2.3 或时间戳是无效的——这类查询参数不改变资源标识,强缓存仍生效,浏览器不会重新拉取。
- 参数式版本(
app.js?v=20261001)对 CDN 和中间代理不可靠,部分会忽略参数做缓存 - 如果无法改构建流程,至少把参数式资源归入“通用静态资源”策略:
max-age=86400, must-revalidate,强制每天验证一次 - 真正可靠的版本控制,永远落在文件路径本身,而非查询参数











