HTML缓存未更新的根本原因是服务端返回了强缓存响应头(如Cache-Control: max-age=86400),浏览器因此不发起新请求;应配置为no-cache, must-revalidate并配合ETag校验或Service Worker主动更新。

部署时 HTML 缓存没更新?先看 Cache-Control 响应头是否生效
浏览器是否缓存 HTML,根本上取决于服务器返回的 HTTP 响应头,而不是你本地改了文件或清了缓存。很多部署后页面“还是旧的”,其实是服务器仍在返回 Cache-Control: public, max-age=3600 这类强缓存策略,导致浏览器压根不发新请求。
验证方法很简单:打开开发者工具 → Network 标签页 → 刷新页面 → 点击 index.html(或主 HTML 文件)→ 查看 Response Headers 中的 Cache-Control 和 Expires 字段。
- 如果看到
max-age=86400或类似长时效值,说明 HTML 被缓存一整天,改完代码也白搭 - 如果看到
no-cache或must-revalidate,但内容仍没变,可能是协商缓存(ETag或Last-Modified)没变,服务器返回了 304 - Nginx/Apache 配置里对
.html文件做了统一缓存规则,容易被忽略
静态 HTML 部署时推荐的缓存策略
HTML 文件本身通常是动态语义(哪怕内容静态),应避免长期强缓存。正确做法是让每次请求都走一次服务器校验,但允许复用未变资源 —— 即用协商缓存,而非强缓存。
例如在 Nginx 中,对 HTML 文件单独配置:
立即学习“前端免费学习笔记(深入)”;
location = /index.html {
add_header Cache-Control "no-cache, must-revalidate";
add_header ETag "";
}
关键点:
- 不要用
no-store(会禁用所有缓存机制,增加带宽和延迟) - 不要依赖
max-age=0,它在部分浏览器中行为不一致 - 显式清空
ETag(如上例)可避免因文件未变而返回 304;若需保留 ETag,请确保构建时文件内容变化能触发 ETag 改变(比如注入哈希)
?v= 参数不是万能的,注意引用链断裂风险
在 HTML 文件 URL 后加 ?v=20261013 确实能绕过缓存,但只对直接访问该 URL 的用户有效。问题在于:
- 用户书签、搜索引擎收录、第三方链接仍指向旧 URL,不会自动跳转
- 如果 HTML 内部引用了
main.css或app.js,这些资源本身没加版本参数,它们仍可能被缓存 - 某些 CDN 或反向代理会忽略查询参数做缓存(尤其当配置了
cache_key不含$args)
所以更稳妥的做法是:把版本号嵌入文件名本身,比如 index.20261013.html,并配合服务端 301 重定向或构建时生成入口映射。否则单靠 URL 参数,只是临时掩耳盗铃。
Service Worker 会劫持刷新逻辑,必须主动更新或卸载
如果你的项目注册了 Service Worker(比如用了 Create React App、Vite PWA 插件或自定义离线方案),那么即使你改了 index.html 并设置了正确的响应头,浏览器也可能继续从 SW 缓存中返回旧 HTML。
常见表现:
- 硬刷新(Ctrl+F5)无效
- Network 面板里 HTML 请求显示
from ServiceWorker,状态码是 200,但内容陈旧 - Application → Service Workers 页面显示 “Waiting” 或 “Active” 但未更新
解决方式不是等它自动更新,而是:
- 开发阶段:勾选 Application → Service Workers →
Update on reload - 生产部署:在新版本 SW 脚本中调用
self.skipWaiting()+clients.claim(),并确保 HTML 中注册逻辑支持热替换 - 紧急回滚:手动执行
navigator.serviceWorker.getRegistration().then(r => r?.unregister())卸载旧 SW
这个环节最容易被跳过,也是上线后“明明部署了却看不到效果”的高频原因。



















