Service Worker 本身不提供语义版本管理与资源回滚能力,需构建、网关与 SW 三层协同:构建层生成带版本路径的 SW 脚本(如 /sw-v1.2.3.js)并动态注入 HTML;网关层按语义版本分流 HTML 与静态资源路径;SW 在 fetch 阶段读取版本标识构造语义化缓存键,实现异步回滚。

构建层:生成带语义版本标识的 SW 脚本
每次发布新版本(如 v1.2.3),构建工具需输出唯一路径的 Service Worker 文件,例如 /sw-v1.2.3.js,并确保 HTML 中注册语句同步更新:
- 避免复用
/sw.js这类无版本路径,防止浏览器强缓存旧 SW - HTML 注入应动态化:服务端渲染或构建时根据当前语义版本写入
navigator.serviceWorker.register('/sw-v1.2.3.js') - SW 文件内容本身不包含 if-else 版本分支逻辑,只负责按运行时传入的版本上下文做缓存读写
网关/CDN 层:按语义版本分流 HTML 入口与静态资源路径
用户首次访问首页时,不是靠前端 JS 判断走哪个版本,而是由边缘节点依据请求特征返回对应语义版本的 HTML:
- 识别依据可为 Cookie(
app-version=v1.2.3)、Header(X-App-Version: v1.2.3)或用户 ID 哈希段 - 返回的 HTML 已预置该版本的 SW 注册地址、资源 base URL(如
<base href="/static/v1.2.3/">)和 meta 版本标记 - 这样从页面加载第一刻起,整个链路(HTML → SW → JS/CSS/图片)就锁定在 v1.2.3 通道内
运行时:fetch 中构造语义化缓存键,支持异步回滚
在 Service Worker 的 fetch 事件中,不能用原始 URL 做缓存 key,否则 v1.2.3 和 v1.2.4 的 /app.js 会互相覆盖:
- 版本标识只能在
fetch阶段读取(如document.cookie或request.headers.get('X-App-Version')),install 阶段不可读 - 缓存 key 应显式携带语义版本,例如:
https://example.com/app.js?v=v1.2.3或caches.open('cache-v1.2.3') - 当后端下发回滚指令(如将所有流量切至 v1.2.2),用户刷新后加载的是 v1.2.2 的 HTML → 注册 v1.2.2 的 SW → fetch 时自动读取 v1.2.2 缓存键 → 命中历史版本资源
回滚执行:不依赖 SW 内部状态,而靠链路快速切换
所谓“异步资源回滚”,本质是毫秒级切换用户所见的完整资源链路,而非在单个 SW 实例里倒退状态:
- 所有历史语义版本的 HTML、SW 脚本、静态资源均保留在 CDN,路径严格隔离(如
/static/v1.2.2/) - 回滚操作只需修改网关规则(如 Nginx rewrite 或 CDN 灰度开关),将符合条件的请求导向 v1.2.2 的 HTML 入口
- 已安装的 v1.2.3 SW 不会立即卸载,但因新 HTML 不再注册它,且后续请求走 v1.2.2 路径,旧缓存自然被隔离、逐步淘汰

















