Service Worker灰度自动回滚本质是构建可控缓存层,通过版本化cacheName、fetch阶段动态分流、多维异常聚合判定(JS错误/资源失败/API异常≥5次/30秒)、失败降级匹配历史快照、服务端健康探测驱动再升级。

Service Worker 本身不能自动回滚,也不保存快照——它只是个事件驱动的脚本。所谓“灰度自动回滚”的本地快照系统,本质是用 SW 搭建一层可控缓存层,配合运行时决策、版本标记和外部信号,让浏览器在检测到异常时,主动切回前一个已验证可用的资源快照。关键不在 SW 多聪明,而在怎么让它“听指挥”、不自作主张。
快照不是存文件,而是存带版本标识的缓存实例
不要试图在 install 阶段把多个版本资源全拉下来。真正可行的是:每个灰度通道(如 v1.2-gray、v1.3-stable)对应一个独立 cacheName,比如 caches.open('sw-cache-v1.2-gray-20260425')。版本号 + 时间戳 + 灰度标签构成唯一快照名,避免混用。
- 构建阶段生成 sw.js?v=1.2-gray,HTML 中动态注入该 URL,防止 SW 被浏览器强缓存
- fetch 事件中,从 document.cookie 或 localStorage 读取当前灰度标识(如 gray_version=1.2),拼出 cacheKey:request.url + '?v=' + gray_version
- 只在 activate 阶段清理过期快照(如保留最近 3 个),用 caches.delete() 主动删掉非活跃 cacheName
灰度开关必须在 fetch 阶段生效,不能靠 install 判断
install 阶段无法读取 cookie、localStorage 或 navigator.onLine,所以“是否走灰度”不能在这里决定。所有分流逻辑必须后移到 fetch 事件中,并与错误监控联动。
- 监听 fetch 请求失败(如 response.status >= 400 或网络中断),记录失败 URL 和当前灰度版本
- 若同一资源在当前灰度通道下连续失败 ≥2 次,且本地存在上一版快照(如 v1.1-stable),则改用该快照中的缓存响应
- 不直接跳转或重定向,而是在 fetch 事件中 return caches.match(cacheKeyFallback),实现无感降级
自动回滚需要可信的触发信号,不能只看单次报错
前端没有“部署完成”信号,也没有服务端健康检查回调。回滚必须基于可验证的行为证据,否则容易误伤。
- 回滚条件至少包含三项:JS 执行报错(通过 window.onerror 捕获)、关键资源加载失败(script/link error)、核心 API 返回 500/timeout(在 fetch 拦截器中标记)
- 三类异常需在 30 秒内集中出现 ≥5 次,才判定为灰度版本不可用,触发快照切换
- 切换后上报事件 {type: 'rollback', from: 'v1.2-gray', to: 'v1.1-stable', reason: 'js_error_burst'},用于后续分析
本地快照系统必须有退出机制,防止锁死旧版
一旦回滚,用户可能长期卡在旧快照里。需设计温和的“再升级”路径,避免形成稳定但陈旧的状态。
- 每次页面加载时,向服务端发起轻量探测请求(如 /health?version=v1.2-gray),检查该灰度通道是否仍被标记为“可用”
- 若服务端返回 410 Gone 或明确 header x-gray-status: deprecated,则清空当前快照缓存,强制重新注册新 SW
- 对已回滚用户,在下次空闲时段(如 visibilitychange → hidden 后 5 秒)静默预加载新版资源,为下次平滑升级铺路










