通过服务工作线程实现离线提示页,具体做法是:在安装阶段预缓存静态离线页;在获取事件中仅对导航请求返回状态码五百零三的构造响应;并且离线页必须自包含,不依赖任何外部资源,从而确保无网环境下的稳定显示。
想象一下,用户在火车上断网,打开你的网站却直接白屏,所有内容都无法加载。其实,完全可以提前准备一张离线提示页,在无网络环境下优雅地告知用户“现在没有网络,请稍后再试”。

长期稳定更新的攒劲资源: >>>点此立即查看<<<
能实现,但必须提前缓存提示页本身,且不能依赖运行时 fetch 拦截失败后跳转——Service Worker 的离线响应必须来自 cache storage 或 self.skipWaiting() 之后的已激活状态。
下面具体拆解实现步骤。
不少开发者认为注册完 Service Worker 就能立即拦截请求,其实并非如此。注册只触发 install 阶段,真正的 fetch 事件要在 activate 之后才生效。如果用户第一次访问就断网,install 阶段直接失败(例如离线页资源尚未加载完),整个离线逻辑从一开始就会崩溃。
navigator.serviceWorker.register() 之后,需要监听 waiting 和 active 状态,必要时调用 sw.waiting.postMessage('skipWaiting') 强制跳过等待。install 事件中,使用 event.waitUntil(caches.open('offline-v1').then(cache => cache.addAll(['/offline.html']))) 将提示页预缓存到本地。注意路径必须与后续 fetch 中匹配的完全一致,否则缓存了也无法读取。install 中缓存动态路由(如 /user/123),/offline.html 必须是静态可预知的路径。浏览器对页面导航(request.destination === 'document')和脚本、CSS、图片等资源请求的处理逻辑不同。离线提示页只应响应导航请求,否则可能将 JS 文件也替换成 HTML,导致页面白屏或报错——本想显示“网络断开”,结果连脚本都损坏了。
if (request.destination === 'document') 进行过滤,避免误劫持 .js、.css 等请求。event.request.mode === 'navigate' 更稳妥,因为有些浏览器直接输入地址栏访问时也会发出 destination: 'document' 请求。fetch(request).catch(...) 做兜底——离线时 fetch 会直接 reject,但必须在 reject 之前就决定返回缓存还是 fallback,而不是等到出错后再补救。直接使用 Response.redirect('/offline.html') 会失败——重定向本身需要网络请求。正确做法是使用 new Response(body, { status: 503, headers: { 'Content-Type': 'text/html' } }) 构造完整响应。
/offline.html 后,需要用 response.text() 提取 body,再重新 new Response(body, options)。不能直接返回缓存对象,因为 cache.match 返回的 response.body 被读取一次后不可再用,需要重新封装。503(Service Unavailable)而非 200,这样在 DevTools 的 Network 面板中能一眼识别出是离线 fallback,调试更直观。/offline.html 自身不引用任何外部资源(如 CDN 字体、第三方 JS),否则它本身也会因加载失败而无法显示。最后,最容易踩的坑是:缓存策略不是“有就行”,而是“install 时必须成功写入 + activate 后能稳定读取”。哪怕只差一个斜杠(例如缓存了 offline.html 却在 fetch 中匹配 /offline.html),或者 HTML 里多写一行 却没缓存该 JS,离线页都会半残。真实环境中,多一个相对路径、少一个 event.waitUntil 包裹,就足以让整个离线流程静默失效。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述