http缓存离线失效,因依赖网络验证且无编程接口;真正离线可用需service worker显式缓存html并按destination分类处理请求,配合network-first策略与精确url匹配。

普通 HTML 缓存机制(即 HTTP 缓存)在离线时基本不发挥作用——它不是为离线设计的,浏览器会直接拒绝导航请求或返回空页,而不是“退而求其次”用缓存的 HTML 渲染。
HTTP 缓存为什么离线就失效
HTTP 缓存依赖服务器响应头(如 Cache-Control、ETag)做决策,但它的核心逻辑是“过期后需验证”。一旦断网,fetch() 或页面导航无法发出请求,验证路径彻底中断。更关键的是:
- 浏览器对
index.html的缓存极其保守:即使它被磁盘缓存了,很多情况下仍会拒绝用过期副本渲染,直接报ERR_INTERNET_DISCONNECTED - HTML 里引用的
<script src="js/app.js"></script>等资源,如果没被缓存或路径不匹配(比如请求的是/js/app.js,但缓存键是js/app.js),整个页面就卡在白屏 - HTTP 缓存没有编程接口——你不能写 JS 判断“现在离线”,然后主动从缓存取 HTML;它完全由浏览器自动触发,且只在“正常网络流程中”生效
真正让 HTML 离线可用的是 Service Worker + CacheStorage
这不是替代 HTTP 缓存,而是绕过它、补充它。Service Worker 在安装阶段主动拉取并存入 CacheStorage,后续通过 fetch 事件拦截请求,手动决定返回缓存还是网络响应。关键点:
- 必须显式缓存
index.html:仅靠Cache-Control: max-age=3600不够,得在install事件里调用caches.open('v1').addAll(['/', '/index.html']) - HTML 推荐用 network-first 策略:在
fetch事件中先fetch(event.request),失败再cache.match(event.request);否则用户永远看不到更新 - 注意
event.request.destination分类:对'document'类型请求单独处理,避免和'script'或'style'混用同一缓存策略 - URL 必须完全一致:缓存
/index.html,但请求是https://example.com/,cache.match()就不会命中——调试时务必打开 Chrome DevTools → Application → Cache Storage 查看实际存入的 key
别踩这些坑:manifest 已废弃,AppCache 会静默失败
还在用 cache.manifest 或 html manifest="app.appcache"?立刻停手。AppCache 有硬伤:
- 清单文件里任意一个资源 404 或超时,整个缓存过程静默失败,后续离线访问直接白屏
- 更新只靠清单文件字节变化——改了 JS 文件但没动 manifest,用户永远拿不到新版本
- 与 HTTP 缓存头冲突:服务器返回
no-cache,AppCache 仍强行缓存并优先使用旧资源 - iOS Safari 对缓存大小限制极严(常截断到 50MB),且
install事件可能永不触发
离线能力的关键不在“缓存多大”,而在“能否精确控制每个请求的响应来源”。HTTP 缓存管加载速度,Service Worker 管离线生存——两者共存,但职责不能混淆。最易忽略的一点:HTML 页面本身必须能自包含运行,即所有依赖的 JS/CSS/图片路径,都得在缓存中存在且 URL 完全匹配。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











