注册Service Worker必须满足HTTPS或localhost安全上下文,install事件中用cache.addAll()预缓存关键资源,fetch事件需手动拦截请求并回退缓存,配合skipWaiting()和clients.claim()实现即时更新。

注册 Service Worker 前必须满足 HTTPS 或 localhost
浏览器只允许在安全上下文中注册 Service Worker,也就是 HTTPS 协议下,或开发时的 localhost。如果你部署在 HTTP 域名(比如 http://example.com),navigator.serviceWorker.register() 会直接失败,控制台报错:Failed to register a ServiceWorker: The document is in an insecure context。
实操建议:
- 生产环境务必配置 HTTPS,哪怕用 Let’s Encrypt 免费证书
- 本地调试可直接用
http://localhost:3000,但不能用http://127.0.0.1:3000(部分老版本 Chrome 不认) - 确保
service-worker.js文件能被直接访问(比如访问https://yoursite.com/service-worker.js返回 200)
缓存静态资源要用 cache.addAll() 而非逐个 cache.put()
想让 PWA 离线加载 HTML/CSS/JS/图片等,最常用方式是在 install 事件里调用 cache.addAll() 预缓存关键资源。它会原子性地缓存整个列表——只要有一个文件 404 或网络失败,全部缓存就中止,避免“半残”缓存状态。
错误写法(易漏、难维护、失败不回滚):
self.addEventListener('install', e => {
e.waitUntil(
caches.open('v1').then(cache =>
cache.put('/index.html', fetch('/index.html')) // ❌ 单个 fetch 失败不影响其他
)
);
});
正确写法:
self.addEventListener('install', e => {
e.waitUntil(
caches.open('v1').then(cache =>
cache.addAll([
'/',
'/index.html',
'/styles/main.css',
'/scripts/app.js',
'/images/logo.png'
])
)
);
});
注意:cache.addAll() 只接受相对路径(相对于 service worker 文件所在 origin),且路径必须是同源的;跨域资源(如 CDN 上的字体)需额外处理,不能直接列在这里。
离线 fallback 必须在 fetch 事件里手动拦截并返回缓存
注册和预缓存只是第一步。真正实现“断网还能打开页面”,得在 fetch 事件中拦截所有网络请求,并在失败时回退到缓存——浏览器不会自动这么做。
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
常见错误现象:安装了 SW、缓存了文件,但关掉网络后刷新页面仍显示 “ERR_INTERNET_DISCONNECTED”。这是因为没写 fetch 监听逻辑,或者只缓存了 JS/CSS,却没缓存 / 对应的 HTML。
基础 fallback 实现要点:
- 优先匹配缓存(
cache.match(request)),命中则直接返回 - 未命中则发起网络请求(
fetch(request)),成功后存入缓存供下次用 - 网络失败时,对 HTML 请求返回一个兜底的离线页(如
/offline.html),对其他资源(如图片)可返回空响应或占位图 - 特别注意:根路径
request.url === location.origin + '/'必须被覆盖,否则首页离线打不开
示例片段(简化版):
self.addEventListener('fetch', e => {
const url = new URL(e.request.url);
if (e.request.destination === 'document') {
e.respondWith(
caches.match(e.request).then(r => r || caches.match('/offline.html'))
);
}
});
skipWaiting() 和 clients.claim() 决定更新是否立即生效
用户首次访问时,SW 安装并激活,一切正常;但当你更新了 service-worker.js,新版本默认要等用户关闭所有旧页面、重新打开才会激活——这导致离线缓存长期不更新,用户实际用的还是旧资源。
解决方法是主动触发更新:
- 在新 SW 的
install事件末尾调用self.skipWaiting(),跳过 waiting 状态 - 在
activate事件里调用self.clients.claim(),让新 SW 立即接管当前页面(包括已打开的 tab) - 注意:这两步要配合使用,只写
skipWaiting()不写claim(),页面仍由旧 SW 控制
另外,如果用了缓存版本号(如 'v2'),记得在 activate 里清理旧缓存,否则磁盘越积越多:
self.addEventListener('activate', e => {
e.waitUntil(
caches.keys().then(keys =>
Promise.all(
keys.filter(k => k !== 'v2').map(k => caches.delete(k))
)
)
);
});
PWA 离线能力的关键不在“注册成功”,而在于你是否真正接管了 fetch 流程,并为每个可能的请求路径都提供了缓存策略——尤其是根路径和 HTML 页面本身,最容易被忽略。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










