HTML缓存问题根源在于CSS/JS等静态资源被强缓存,而非index.html本身;应为静态资源添加哈希后缀并配immutable,HTML则用no-cache+ETag协商缓存。

HTML缓存问题的根源几乎从不在于 index.html 本身被“缓存坏了”,而在于你没意识到它只是个入口,真正被强缓存的是它引用的 css、js、img 等资源——而且浏览器对这些资源的缓存策略,和你写的 HTML 文件完全无关。
为什么改了 CSS/JS 但页面没变
典型现象:构建部署后,用户刷新页面,样式还是旧的,控制台 Network 面板里 app.js 和 style.css 的响应状态是 200 (from disk cache) 或 304,但内容明显不是最新版。
根本原因不是 HTML 缓存时间设错了,而是服务器给这些静态资源返回了类似 Cache-Control: public, max-age=31536000, immutable 的响应头——浏览器直接信了,十年内都不再校验。
- 检查方式:用
curl -I https://yoursite.com/app.js看响应头,重点关注Cache-Control和ETag - 错误做法:只给
index.html设no-cache,却放任main.a1b2c3.js被缓存一整年 - 正确做法:静态资源走哈希文件名(如
main.a1b2c3.js),HTML 中自动注入新路径;同时确保服务器对这类带哈希的文件返回immutable——这样既安全又高效
为什么加了 ?v=1.2.3 还是不生效
常见于手写构建或 CMS 模板中:你在 <script src="app.js?v=1.2.3"></script> 里加了版本号,但服务器上 app.js 文件本身没更新,或者 CDN 缓存了带 ?v= 的 URL。
立即学习“前端免费学习笔记(深入)”;
关键点:?v= 参数只有在服务端实际返回新内容时才起作用;否则浏览器会缓存那个“旧内容+新参数”的组合。
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- CDN 常把带查询参数的 URL 当作不同资源,但有些配置会忽略 query string ——需确认 CDN 缓存键(cache key)是否包含
query - 本地开发用
file://协议打开 HTML?那?v=完全无效,浏览器不发 HTTP 请求 - 别用
new Date().getTime()动态拼接(如app.js?t=1728524400123)——这会让每次请求都绕过缓存,失去所有缓存收益,且可能触发服务器限流
为什么 <meta http-equiv="Cache-Control"> 不起作用
这种写法在现代浏览器中基本被无视,尤其对 <link> 和 <script></script> 引入的外部资源完全无效。它只能影响当前 HTML 文档本身的渲染行为(且优先级远低于 HTTP 响应头)。
更麻烦的是:如果服务器已返回 Cache-Control: public, max-age=3600,那么 HTML 里的 <meta> 标签连这个 HTML 自己都管不住。
- 不要在生产环境用
<meta http-equiv="Cache-Control" content="no-cache">来“解决”缓存问题 - 它无法覆盖服务器响应头,也不能影响子资源;仅在极老浏览器或某些特殊代理下有微弱效果
- 真要控制 HTML 缓存,请改服务器配置(Nginx/Apache)或托管平台(Vercel/Netlify)的 headers 设置
Service Worker 导致强制刷新也无效
一旦注册了 Service Worker,它就接管了所有网络请求。如果你的 SW 脚本里写了 event.respondWith(cache.match(event.request)),但没做版本比对、没清理旧缓存,那 Ctrl+F5 都白搭——因为请求根本没发到网络层,SW 直接返回了缓存里的旧 HTML 或 JS。
这是最隐蔽也最难排查的一层:你以为清了浏览器缓存,其实 SW 在背后悄悄喂你旧包。
- 检查方式:打开开发者工具 → Application → Service Workers,看是否已激活、是否有 “Update on reload” 勾选
- 临时解决:点 “Unregister”,或勾选 “Skip waiting” + “Update on reload”,再刷新
- 长期方案:SW 更新逻辑必须包含版本标识(如 CACHE_NAME = 'v2'),并在
install阶段清理旧 cache,不能无脑cache.addAll()
缓存机制的复杂性不在 HTML 本身,而在它牵扯的每一层:HTTP 响应头、构建输出、CDN 规则、Service Worker 脚本、甚至浏览器对 immutable 的实现细节。漏掉任何一层,都可能让版本号、哈希、强制刷新全部失效。


















