Service Worker 无法接收远程强制更新指令,其更新依赖前端主动检测版本变化、触发注册流程并引导用户刷新。关键前提是 index.html 必须禁用 HTTP 缓存(如设 Cache-Control: no-cache),否则浏览器将加载旧版 HTML 而无法引用新 SW;浏览器仅在页面刷新、24 小时超时或显式 register 时检查 SW 更新;前端可通过轮询 /version.json 检测更新,在 waiting 状态调用 skipWaiting 并提示用户 reload;新 SW 需在 install 阶段 self.skipWaiting()、activate 阶段清理旧缓存并 clients.claim() 以立即生效。

Service Worker 本身不直接“接收远程强制更新指令”,它没有监听服务器命令的内置能力。所谓“强制更新”,实际是前端主动检测版本变化 + 触发 Service Worker 更新流程 + 引导用户刷新页面的一整套协作机制。核心不在“远程下发指令”,而在“如何让新版本生效且不被旧缓存阻断”。
关键前提:确保 index.html 不被 HTTP 缓存锁定
很多 PWA 更新失败,根本原因不是 Service Worker 没更新,而是浏览器压根没加载到新版的 index.html——它被 CDN 或 Nginx 缓存了 24 小时,里面仍引用着旧版 JS 和旧版 service-worker.js 的哈希名。
- 必须将 index.html 的 Cache-Control 设为 no-cache 或 max-age=0,让它每次访问都向服务器发起条件请求(带 ETag/Last-Modified)
- Nginx 示例配置:
location = /index.html { add_header Cache-Control "no-cache"; } - CDN(如 Cloudflare)需单独设置 index.html 的缓存规则,排除在全局缓存策略之外
Service Worker 自动更新的触发条件
浏览器只在以下任一情况发生时,才会尝试获取并安装新的 Service Worker:
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
- 用户刷新页面(F5 或地址栏回车),且当前页面的 HTML 是从网络加载的(非强缓存)
- 页面打开后超过 24 小时未刷新(Chrome 默认策略,会自动检查 sw.js 是否有变更)
- 代码中显式调用
navigator.serviceWorker.register('/sw.js', { updateViaCache: 'none' })
注意:只要服务端返回的 service-worker.js 文件内容字节不同(例如注入新版本号、修改缓存列表),浏览器就会启动新 Worker 的 install 流程。
前端主动检测 + 提示用户刷新
靠用户碰巧刷新不可控,需要前端主动感知更新并引导。典型做法是结合 AppUpdater 模式(如 go-app)或自定义轮询:
- 在页面中定期(如每 5 分钟)fetch 一个轻量版版本文件(如
/version.json),比对当前运行版本与服务端声明版本 - 若发现不一致,调用
navigator.serviceWorker.getRegistration()获取注册实例 - 监听
waiting状态(新 SW 已安装但未激活),然后调用registration.waiting.postMessage('skipWaiting') - 最后提示用户:“有新版本,点击刷新立即生效”——点击后执行
window.location.reload(true)
避免“静默卡住”:清理旧缓存与跳过等待
新 Service Worker 安装后,默认不会立刻接管页面,除非旧 Worker 已无控制页。要实现无缝强制更新,需在新 SW 的 install 阶段主动跳过等待:
- 在 service-worker.js 中加入:
self.addEventListener('install', e => e.waitUntil(self.skipWaiting())) - 在
activate阶段清理旧缓存:caches.keys().then(keys => Promise.all(keys.filter(k => !k.includes(CURRENT_VERSION)).map(k => caches.delete(k)))) - 同时调用
clients.claim(),确保新 SW 立即控制当前页面

















