PWA离线页面需通过Service Worker预缓存/offline.html、在fetch事件中主动fallback并专治导航请求来实现。必须显式预缓存、拦截document请求、返回缓存离线页,并在真实断网下验证。

当网络完全中断时,PWA 应用需立即呈现一个明确、友好且功能可用的离线页面,而不是浏览器默认的“无法连接”错误。这需要从 Service Worker 拦截请求、预缓存离线页、正确响应失败请求三方面协同实现。
注册并预缓存离线页面文件
在 Service Worker 的 install 事件中,必须将离线页(如 /offline.html)与其他静态资源一并加入缓存。不能只靠 fetch 时兜底——若该页面本身未预缓存,首次离线访问仍会失败。
- 确保离线页是纯静态 HTML,不依赖外部 JS/CSS(或把它们也一并缓存)
- 使用
caches.open('v1').addAll([...])显式包含'/offline.html' - 推荐路径为根目录下的绝对路径(如
/offline.html),避免相对路径解析歧义
在 fetch 事件中主动返回离线页
当请求无法命中缓存、又无法通过网络获取时,应主动 fallback 到已缓存的离线页,而非抛出异常或返回空响应。
把任意文章或文档内容转换成精美的全屏翻页 HTML 演示文件(幻灯片风格)。当用户发来一篇文章、文档链接、Markdown 内容、或粘贴的文本,并且希望生成演示用的 HTML 时触发。支持任意内容来源:iWiki 链接、KM 链接、本地文件路径、直接粘贴的文本。生成的 HTML 文件保存到本地工作区,并通过企微直接发送给用户。触发词示例:帮我把这篇文章做成PPT、转成演示文档、生成HTML幻灯片、做个演示、转成可以演示的格式、article to deck、make a slide。
- 在
fetch事件的respondWith中,caches.match(request)未命中后,调用fetch(request)并捕获其 reject - 在
catch分支里,再次调用caches.match('/offline.html')获取离线页响应 - 若连离线页都未缓存成功,可返回一个极简内联 HTML 响应作为最后保障(例如
new Response('<h1>离线中</h1>', {headers: {'Content-Type': 'text/html'}}))
设置离线页为自定义导航失败兜底
除资源请求外,用户手动输入 URL 或点击内部跳转时,也可能触发导航请求失败。需确保这些请求也被 Service Worker 拦截并导向离线页。
- 对
request.destination === 'document'的请求(即页面导航),优先尝试缓存匹配;未命中则直接返回离线页,不走网络回退 - 可在
fetch逻辑中加判断:if (request.mode === 'navigate') { return caches.match('/offline.html') || ... } - 离线页自身应具备基础交互能力:比如显示当前状态、提供刷新按钮、支持已缓存的本地操作(如查看草稿)
验证与调试关键点
配置完成后,必须在真实断网环境下验证效果,尤其注意 Safari 和 Chrome 的行为差异。
- 在 Chrome DevTools 的 Application → Service Workers 中勾选 “Offline”,再刷新页面
- 在 Safari 中需先启用开发菜单,打开 Web 检查器 → Application → Cache Storage,确认
/offline.html已出现在对应缓存中 - 若页面空白或报错,检查控制台是否提示
Failed to load resource: net::ERR_INTERNET_DISCONNECTED—— 这说明 Service Worker 未拦截该请求,可能因 sw.js 未注册成功或 scope 范围过小

















