React JS PWA中Service Worker推送通知无响应问题求助
问题分析与修复方案
看了你的代码,发现几个关键问题导致Service Worker的install/activate事件没触发、推送功能完全失效,咱们一步步来解决:
1. 最核心的问题:Service Worker注册逻辑根本没执行
你的index.js里只写了serviceWorker.register(),但worker.js中的register函数是导出的模块,如果index.js没有正确导入这个函数,注册逻辑等于没跑!这就是为什么控制台连register called都没输出的原因。
2. Service Worker全局对象用错了
Service Worker运行在独立的后台上下文里,没有window这个对象!你代码里的window.self、window.registration全是错误的引用——SW里的全局对象是self,所有事件绑定、API调用都得基于它。
3. Activate事件没等待异步操作完成
你在activate事件里直接调用了pushManager.subscribe这个异步操作,但没把它放进event.waitUntil()里。这会导致事件在订阅请求完成前就结束,订阅逻辑直接被中断,后续自然收不到推送。
4. 额外的细节问题
- 旧的Service Worker可能还缓存着,导致新代码不生效,需要加
skipWaiting()强制激活新SW urlBase64ToUint8Array里的window.atob也要改成self.atob,SW里没有window
修改后的完整代码
index.js(确保正确导入并调用注册函数)
// 先导入worker里的注册函数 import { register } from './worker.js'; // 调用注册逻辑 register();
worker.js(修复所有错误点)
const publicVapidKey = "BOdud_KdO16dL40D56LbksLa6ElXFAJu-2XEdIKQUmehzomo6FES2jJ1niaUYrCobfI8U5rkqeQNjPB03mKZMvY"; export const register = () => { console.log('register called'); if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/worker.js') .then((responseRegister) => { console.log('register object', responseRegister); window.registration = responseRegister; }) .catch((err) => { console.log('error is ', err); }); } }; export const unregister = () => { console.log("unregister called"); if ('serviceWorker' in navigator) { navigator.serviceWorker.getRegistrations() .then(function (registrations) { console.log('registrations', registrations); for (let registration of registrations) { registration.unregister(); } }).catch(function (err) { console.log('Service Worker registration failed: ', err); }); } }; // 修复:用self绑定install事件,添加skipWaiting强制激活新SW self.addEventListener('install', (event) => { console.log('service worker installed', event); event.waitUntil(self.skipWaiting()); }); // 修复:用self绑定activate事件,用waitUntil包裹异步订阅逻辑 self.addEventListener('activate', (event) => { console.log('service worker activated', event); // 让SW控制所有打开的页面 event.waitUntil(self.clients.claim()); // 把订阅逻辑放进waitUntil,确保事件等待异步操作完成 event.waitUntil( self.registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(publicVapidKey) }).then((subscription) => { console.log('subscription', subscription); }).catch((err) => { console.log('error in subscribing to push', err); }) ); }); // 修复:用self绑定push事件,用self.registration显示通知 self.addEventListener("push", (e) => { const data = e.data.json(); console.log("Push Recieved..."); self.registration.showNotification( data.title, { body: "Notified by Traversy Media!", } ); }); function urlBase64ToUint8Array(base64String) { const padding = "=".repeat((4 - base64String.length % 4) % 4); const base64 = (base64String + padding) .replace(/\-/g, "+") .replace(/_/g, "/"); const rawData = self.atob(base64); // SW里用self.atob替代window.atob const outputArray = new Uint8Array(rawData.length); for (let i = 0; i < rawData.length; ++i) { outputArray[i] = rawData.charCodeAt(i); } return outputArray; }
测试步骤
- 打开Chrome DevTools的Application > Service Workers面板,勾选
Update on reload,确保每次刷新都加载最新的SW - 刷新页面后,检查面板里是否能看到你的worker.js,状态应为
activated - 测试推送前,确认你的VAPID公钥和后端私钥匹配,且后端推送请求的格式正确
- 注意:只有HTTPS环境(localhost除外)才能正常使用推送功能
内容的提问来源于stack exchange,提问作者ash1102
相关产品推荐
相关产品推荐

