HTML必须短缓存或禁用强缓存,否则新哈希资源无法加载;图片URL应加构建时注入的版本参数;Service Worker缓存名须带版本号并清理旧缓存;/version.json和HTML自身是关键缓存断点。

靠 URL 变更强制刷新缓存,不是改文件名、也不是等浏览器自动过期。HTML 本身不控制缓存更新逻辑,真正起效的是构建哈希 + 服务端响应头 + 客户端请求路径三者协同。
为什么直接改 HTML 里的 src 或 href 没用
浏览器完全忽略 <meta http-equiv="Cache-Control">,HTML 文件的缓存行为只由服务器返回的 HTTP 响应头(如 Cache-Control: public, max-age=31536000)决定。一旦 HTML 被强缓存,里面写的 app.a1b2c3.js 就永远不变——哪怕你已部署了 app.x4y5z6.js,用户也加载不到。
- 常见现象:
index.html在 Network 面板显示200 (from memory cache),但 JS 报错或功能缺失 - 根本原因:HTML 没重新请求,新哈希路径根本没被解析执行
- 解决前提:服务端必须对 HTML 设置较短缓存(如
max-age=60)或禁用强缓存(no-cache)
img 和 background-image 的 URL 版本参数怎么加才安全
给图片 URL 加查询参数(如 ?v=20261010)是绕过浏览器缓存最直接的方式,但参数不能随便写。
- 别用
Math.random()或时间戳(?t=+new Date()):每次渲染都触发新请求,彻底废掉缓存价值 - 推荐用构建时注入的值:Vite 中用
import.meta.env.VITE_BUILD_TIME,Webpack 中用html-webpack-plugin的templateParameters注入version - S3/CDN 不校验查询参数,所以
photo.jpg?v=2.1和photo.jpg读取的是同一份文件,纯为欺骗浏览器 - CSS 中写死
url(logo.png?v=2.1)可行,但更健壮的做法是构建时自动替换,避免手误
Service Worker 缓存名必须带版本号,否则等于没更新
Service Worker 的缓存空间靠 caches.open('pages-v2.1.0') 这种字符串标识,浏览器据此隔离不同版本资源。复用同一个名字(如 'pages')会导致新旧文件混存,离线时随机加载出错。
立即学习“前端免费学习笔记(深入)”;
- 每次发布必须变更缓存名,格式建议为
pages-${VERSION}或assets-${BUILD_HASH} -
install阶段调用cache.addAll(['/index.html', '/style.css'])显式缓存 HTML —— 漏掉它,离线就是白屏 -
activate阶段清理旧缓存:caches.delete('pages-v2.0.0'),但绝不能删当前正在用的缓存名 - HTML 本身不该长期缓存进
CacheStorage:它是动态入口,应走network-first策略,其他静态资源才用cache-first
容易被忽略的两个缓存层:HTML 自身和 /version.json
很多人只盯着 JS/CSS 图片,却忘了这两处才是版本同步的断点。
- HTML 文件若被 CDN 或 Nginx 强缓存(
max-age=31536000),新版本永远到不了用户浏览器 -
/version.json必须禁用所有缓存:Cache-Control: no-cache, must-revalidate,前端 fetch 时显式设cache: 'no-store',否则浏览器可能返回旧版 JSON - 如果用
meta标签注入版本(如<meta name="app-version" content="v2.1.0">),SW 的fetch事件里要解析该值并校验,不匹配就拒绝缓存响应
真正难的不是加个 ?v=xxx,而是让 HTML、JS、CSS、图片、SW 缓存名、后端接口全部在同一个版本语义下联动更新。漏掉任意一环,用户看到的就是“一半新一半旧”的页面。



















