?v=参数在生产环境常失效,因cdn/nginx默认忽略查询字符串缓存键,http/2浏览器可能复用主体相同资源;应改用contenthash文件名(如main.a1b2c3d4.css)配合immutable强缓存头。

直接改 link 标签的 href 值加查询参数(如 ?v=2.3.1)最简单,但生产环境大概率失效——CDN 和浏览器缓存行为不认这个“版本号”,只看 URL 主体或压根忽略参数。
为什么 ?v=xxx 在线上经常不起作用
浏览器和中间层(比如 Cloudflare、Nginx 代理)对带 ? 的 URL 处理不一致:
- 部分 CDN 默认关闭 “Include query string” 缓存键,
style.css?v=1.0.0和style.css?v=1.0.1被当成同一个 URL 返回旧缓存 - Nginx 若配置了
proxy_cache_key $scheme$host$request_uri,它确实包含参数,但很多现网配置用的是$scheme$host$uri,$uri不含查询参数 - HTTP/2 下某些浏览器会复用同一主体资源的响应,即使参数不同
- 运维发布时手动改 HTML 里的
v=值,漏一处就导致部分页面加载旧 CSS
Webpack/Vite 中该用 contenthash 而不是时间戳或 commit hash
构建工具生成的文件名哈希(如 main.a1b2c3d4.css)才是真·版本控制:内容一变,文件名就变,URL 必然不同,缓存自然失效。
-
webpack:配MiniCssExtractPlugin.filename: '[name].[contenthash:8].css',再用HtmlWebpackPlugin自动替换 HTML 中的href -
Vite:默认开启build.rollupOptions.output.assetFileNames的 hash 输出,只要 HTML 里写<link href="style.css">,插件会自动映射为带 hash 的真实路径 - 别用
?v=${Date.now()}或?v=${git rev-parse --short HEAD}—— 前者让每次构建都失效长期缓存,后者在 CI 环境无 .git 目录时直接报错 - 如果 CSS 是通过
import './index.css'加载且被抽成独立文件,要关掉css.codeSplit,否则 import 路径和实际输出文件名对不上,404
Nginx 配置必须配合哈希文件名才安全
光靠构建阶段重命名不够,服务器响应头得告诉浏览器:“这文件一年内不会变”,否则它仍可能发验证请求(If-None-Match)或降级缓存策略。
- 匹配哈希静态资源:
location ~* \.(css|js|png|woff2?)$ - 设长缓存:
expires 1y;+add_header Cache-Control "public, immutable"; - 单独处理 HTML:
location ~* \.html$ { add_header Cache-Control "no-cache, must-revalidate"; },避免 HTML 缓存太久导致引用了过期的哈希 CSS 链接 - 上线后必须检查响应头:用
curl -I https://yoursite.com/main.a1b2c3d4.css确认返回了Cache-Control: public, immutable
真正卡住人的从来不是“怎么加版本号”,而是 CDN 缓存层级比你想象中更深、更难清——哪怕你本地 curl 已看到新 CSS,用户手机上仍可能卡在三级 CDN 节点的旧缓存里。上线后务必调用 CDN purge 接口,清掉所有旧哈希前缀的 CSS URL,不能只等 TTL 过期。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











