service worker 无法直接实现异步灰度回滚与本地快照管理,需构建、网关、sw 运行时三层协同:构建生成带语义版本标识的资源及 sw 脚本;网关按用户特征分发对应版本 html 入口;sw 在 fetch 中基于运行时版本构造隔离缓存键。

Service Worker 本身无法实现“异步灰度回滚”或“本地静态快照管理”,它不保存资源副本,也不支持运行时按需加载多个版本的完整资源集合。所谓“快照”是模拟行为,本质依赖三方面协同:构建阶段生成带语义化版本标识的资源与 SW 脚本、CDN/网关按用户特征分发对应 HTML 入口、SW 在 fetch 中构造带版本上下文的缓存键并隔离存储。
构建层:产出可区分、可追溯的静态资源快照
每次发布都应生成唯一且语义明确的版本标识(如 v2.4.1 或 20260502-abc123),而非仅靠时间戳或哈希——后者易导致无变更时重复缓存。该标识需贯穿以下环节:
- 所有静态资源 URL 带查询参数或路径前缀,例如
/js/app.js?v=v2.4.1或/static/v2.4.1/app.js - Service Worker 脚本本身命名为
sw-v2.4.1.js,避免复用同一 URL 导致浏览器强缓存旧版 - 构建产物中生成资源清单(如 manifest.json),精确记录每个文件的带版本完整路径,供 SW install 阶段读取并预缓存
- HTML 模板由服务端或构建时动态注入对应版本的注册代码:
navigator.serviceWorker.register('/sw-v2.4.1.js')
网关层:把灰度决策前置到 HTML 入口分发
灰度不是前端 JS 控制的,而是由边缘节点根据请求特征实时决定返回哪个版本的 HTML 页面。这是“异步回滚”的前提——无需等待客户端重载 SW 或刷新页面,只要切换入口,整个链路立即生效。
- 识别依据包括 Cookie(如
gray-version=v2.4.1)、Header(X-Gray-Version: v2.4.1)、IP 段或设备指纹 - 返回的 HTML 中已固化该版本的 SW 注册地址、静态资源 base URL、关键配置接口路径
- 确保不同灰度通道的资源路径完全隔离,例如
/static/v2.4.1/和/static/v2.3.0/不共享 CDN 缓存
Service Worker 运行时:用版本上下文构造缓存键
fetch 事件中不能直接用原始 URL 做 cache key,否则 v2.3.0 和 v2.4.1 的 /app.js 会互相覆盖。必须引入运行时可读的版本标识来区分缓存条目。
- 版本标识只能在 fetch 阶段读取(如
document.cookie或request.headers.get('x-gray-version')),install/activate 阶段不可访问 - 缓存名建议统一为
static,但 cache key 必须拼接版本,例如:https://example.com/app.js?v=v2.4.1 - 示例逻辑:
self.addEventListener('fetch', event => { const url = new URL(event.request.url); const version = getCookieVersion() || 'v2.3.0'; // fallback 安全兜底 const cacheKey = url.origin + url.pathname + '?v=' + version; event.respondWith( caches.match(cacheKey).then(res => res || fetch(event.request)) ); }); - 避免使用
credentials: 'include'的请求进缓存,除非显式配置{ ignoreVary: true },否则因凭据不匹配导致 match 失败
回滚执行:靠链路切换,而非 SW 内部状态倒退
所谓“异步灰度回滚”,是指在不中断用户当前会话的前提下,让新打开的页面或后续导航自动进入历史版本通道。它不依赖 SW 主动卸载或降级,而是快速修改网关规则,将符合条件的流量导向旧版 HTML 入口。
- 所有历史版本的 HTML、SW 脚本、静态资源均保留在 CDN,路径按版本隔离,长期保留(至少保留最近 3 个主版本)
- 回滚操作只需更新网关策略(如 Nginx rewrite、Cloudflare Rules、API 网关路由表),毫秒级生效
- 已激活的旧版 SW 仍可继续工作,其缓存内容不受影响;新版 SW 不会干扰旧版用户,因它们注册在不同 scope 或根本未被加载
- 若需强制已有页面也切回旧版,可通过 postMessage 通知页面 reload,并跳转至旧版 HTML URL










