html离线运行唯一可靠方式是service worker,需https(localhost除外)、同源注册、两次刷新或skipwaiting生效;缓存须完整包含html及其依赖资源,fetch事件中按request.destination精准分流请求。

HTML 离线运行靠的是 Service Worker,不是 meta 标签或 manifest 文件
很多人以为加个 <meta http-equiv="Cache-Control" content="max-age=3600"> 或扔个 manifest.json 就能离线打开 HTML,实际根本不行。现代浏览器(Chrome/Firefox/Edge)已废弃 Application Cache(即 manifest),唯一可靠路径是注册并激活 ServiceWorker,它才能拦截网络请求、返回缓存资源。
关键点:Service Worker 必须通过 HTTPS 提供(localhost 除外),且注册脚本必须和页面同源;注册后不会立即生效,需刷新两次或调用 skipWaiting()。
- 只在支持
navigator.serviceWorker的浏览器中启用,旧版 Safari 需降级处理 -
service-worker.js文件不能被其他缓存策略干扰(比如 Nginx 返回了Cache-Control: no-store,会导致注册失败) - 首次加载页面时注册成功,但
install事件里的缓存逻辑只对后续访问生效
缓存静态 HTML 页面的正确写法:用 cache.addAll() 预加载关键资源
直接 fetch index.html 并 put 到 cache 是错的——你得把 HTML + 它依赖的 JS/CSS/图片一并缓存,否则离线时 HTML 加载了,但 <script src="app.js"></script> 404。
常见错误现象:Failed to load resource: net::ERR_FAILED 出现在控制台,但页面空白或功能缺失,本质是缓存不完整。
- 在
install事件里用cache.addAll(['/', '/style.css', '/app.js', '/logo.png']),注意路径必须是相对根路径(/表示站点根目录) - 不要缓存带查询参数的 URL(如
/data.json?v=1.2),不同参数会被视为不同键,容易爆缓存空间 - HTML 文件本身建议用
Stale-While-Revalidate策略:先返回缓存,再后台更新,避免用户看到过期内容又卡住
fetch 事件里怎么判断该走缓存还是网络:优先匹配 HTML,其余走缓存兜底
Service Worker 的 fetch 事件是离线逻辑的核心开关。不能无差别缓存所有请求(比如 API 接口不该离线返回旧数据),也不能全走网络(那就没离线意义)。
典型误配:event.respondWith(caches.match(event.request)) 单行代码看似简洁,但会把 POST 请求、带凭证的请求也去匹配缓存,导致登录态失效或表单提交静默失败。
- 用
event.request.destination === 'document'精准识别 HTML 页面请求(即地址栏输入或点击链接跳转) - 对
destination === 'script'或'style'的请求,可直接caches.match()返回缓存 - 对
destination === 'json'或'image',建议加一层判断:有缓存就返回,没缓存才 fallback 到网络(避免离线时白屏)
调试离线行为最有效的三步:Application 面板 + skipWaiting + 模拟 offline
光看代码没法确认是否真离线可用。Chrome DevTools 的 Application → Service Workers 面板才是真相所在,很多问题在这里一眼暴露。
容易踩的坑:Update on reload 开关开着,但没点 skipWaiting,新 SW 一直 waiting,旧逻辑还在跑;或者勾选了 Offline 却忘了禁用“Disable cache”,导致你以为离线失败,其实是 DevTools 自己绕过了缓存。
- 每次改完
service-worker.js,先点Unregister再刷新,避免旧版本残留 - 确保
skipWaiting()放在新 SW 的install事件里(不是activate),否则无法立即接管 - 测试前清空
Cache Storage和Service Workers,防止旧缓存干扰验证
离线能力不是“加个缓存就完事”,而是请求生命周期的重定向控制。最常被忽略的是 HTML 依赖图的完整性——少缓一个 favicon.ico 都可能让整个页面在某些浏览器里拒绝渲染。动手前,先用 Network 面板录一次完整加载,把所有 status 200 的资源列出来,再决定哪些进 cache。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











