CF FIELDBOOK/实践

受保护的 PWA

页面还在,连接已断

手机上已经安装的 PWA 能显示标题和旧页面,点击发送却失败。服务端程序仍然健康,桌面浏览器重新登录也未必能让手机恢复。这种表现很容易让人去重启模型、重发消息,实际断开的却可能是入口会话。

2026-07-28,作者维护的一个受保护的 PWA 就遇到了这个问题。普通 Safari 与安装后的 PWA 都显示不可用页面,但请求没有到达源站:Cloudflare Access 正在要求重新登录,service worker 却仍能从缓存提供应用外壳。页面把请求失败解释成后端 provider 不可用,用户也没有一条确实走网络的重连入口。

先看三种彼此独立的状态#

状态 控制什么 不能从它推断什么
Access 会话 当前浏览环境是否通过这个应用的入口认证 已登录的另一个浏览环境也通过了认证
service worker 与缓存 哪一版 service worker 控制页面,哪些资源能从本机取到 网络能到达受保护的 API
源站当前版本 服务器正在提供哪份应用文件与接口 用户设备已经取到了该版本

Cloudflare Access 的应用、策略与全局会话有各自的持续时间,登录资格与当前会话也不是同一个期限。Access session management 官方说明。在这次事故中,Safari 和 standalone PWA 的会话需要分别验收;这是一项实际设备观察,不能依靠在另一处登录来推断。

service worker 可以拦截请求并从缓存返回资源,新 worker 安装后还可能等待旧页面退出才激活。因此服务器已更新和设备仍显示旧壳可以同时成立。MDN:Using Service Workers。

当时的路径可以画成两条:

打开首页 → service worker → 缓存外壳:能显示
请求 API → Cloudflare Access → 要求认证:尚未到达源站

第一条成功,无法证明第二条成功。也不能把页面里的错误文案当作故障所在层的证据。

PWA 重连:给用户一条真正走网络的路#

这个 PWA 的修复增加了一个精确的 /api/reconnect 导航入口。它只用于重新连接:service worker 不用首页缓存代替这条请求;Access 可以拦截它并完成认证;通过以后,源站用同源的相对重定向返回首页。这个请求不发送消息、不重放任务,也不修改会话内容。

界面同时把错误改成「私人连接不可用」,提供用户可点击的重连动作。这样用户知道应先恢复入口,不必猜测模型或服务端程序已经停止。

路径的要点是 真正走网络,而且不产生业务副作用。单纯刷新一个被 cache-first 策略接管的首页,可能只重新拿到同一份旧页面。重连路径、业务 API 与 Access 的认证路径也不能被 SPA navigation fallback 变成首页 HTML;返回 200 的首页不是成功的 API 响应。

旧 worker 也可能挡住修复本身#

增加重连按钮后,还需要解决安装设备上的旧版本。那次恢复准备了一份只改变 service worker 的配对恢复版本,在一个精确、临时的脚本路径窗口内让设备取得更新;整个首页继续受保护。随后恢复正常版本、删除临时入口与规则,再确认匿名首页和 worker 脚本都重新要求 Access 认证。

这是一项带设备验收和清理的历史事故处置,不能变成长期配置建议。不要为了让 PWA 更新方便,永久 Bypass /sw.js 或整个应用。 Bypass 的含义就是让符合规则的请求绕过 Access;是否需要公开某个资源,应从该资源本来能否公开来决定,而不能用“页面终于能开了”作为依据。Cloudflare Access policies 官方说明。

日常修复应优先使用已经设计好的网络重连与更新路径。若设备仍受旧 worker 控制,先记录当前 controller、waiting worker、脚本版本与网络返回,再决定该设备的恢复方法。删除全部浏览器数据可能丢弃草稿和本机偏好,也会抹去定位旧版本的线索,适合在明确后果后按具体设备操作。

这次恢复证明了哪些结果#

2026-07-28 的观察 说明什么
服务端健康,但网络请求未到达源站 故障首先发生在入口与浏览器路径
重连路径确实经过网络与 Access 用户有机会更新该环境的入口会话
实际 iPhone standalone PWA 重新打开后取得在线历史与状态 这台安装设备恢复了实际应用读取
临时恢复规则移除后,匿名首页与脚本重新受到保护 恢复没有依赖永久开放入口
正常 worker 重新获取,业务接口成功响应 设备回到正常版本的受保护路径

本文根据这份历史故障重构。2026-10-03 编辑时查阅了官方机制,没有重新登录原系统、重做 iPhone 验收或确认今天的浏览器版本;一次恢复也不保证所有设备、未来更新与登出都已覆盖。

怎样验证自己的 PWA#

使用自己的测试账号和无私人内容的样本页面。保留一个能独立检查源站健康的入口;下面的会话与更新检查放在测试设备或测试应用中进行。

  1. 普通浏览器和安装后的 PWA 分别打开,记录它们各自的登录状态;不要把一处成功当作两处成功。
  2. 让测试会话过期或退出,再打开旧页面。确认缓存外壳可以显示时,界面仍明确提示连接问题,业务操作没有自动重发。
  3. 点击重连,在开发者工具或应用日志中确认请求真的到达网络,并在认证完成后返回同源页面;它不创建业务记录。
  4. 发布只改变一个可见版本标记的测试更新,观察新 worker 是否仍 waiting;完成更新后再确认 controller 与标记一致。
  5. 分别检查匿名首页、API、worker 脚本,以及登录后的实际读取。若用过任何临时恢复规则,移除后重查这些请求。

如果应用没有 service worker,先检查 Access 会话与普通 HTTP 路径即可。若问题已经到达源站并由业务接口明确拒绝,就沿该接口继续诊断,不要再把所有失败归为缓存。手册:私人服务的门与钥匙解释入口与应用权限的分工;私有状态页进一步区分入口健康与源站健康。

术语 / FIELD NOTES

在词表中继续阅读