WordPress Web推送插件:Service Worker重复发送通知问题
嘿,针对你遇到的这个问题——用户订阅后欢迎通知正常,但新文章推送时部分用户收到多条通知且仅一条带跳转链接,我结合你提供的代码梳理了根源和修复方案:
问题根源分析
Service Worker缺失Push事件处理逻辑:你当前的
service-worker.js只监听了install、activate和message事件,完全没有处理推送核心的push事件。这意味着通知展示可能依赖外部加载的脚本(比如你注册SW时带的notifymsgjs参数对应的文件),如果外部脚本重复加载或SW更新时重复绑定事件,就会导致多条通知。Service Worker重复注册与强制更新:在
generate-token.js里,每次UDID变化就会重新注册SW,还立刻调用reg.update()。频繁的更新会让SW多次激活,可能触发重复的推送监听逻辑。推送Payload处理不严谨:如果后端发送的推送数据没有稳定携带跳转链接,或者前端处理逻辑只有第一次触发时解析链接,后续重复通知就会丢失链接信息。
具体修复步骤
1. 完善Service Worker的Push事件处理
修改service-worker.js,添加push和notificationclick事件监听,统一接管通知逻辑,避免依赖外部脚本的不确定性:
self.addEventListener('install', function(event) { console.log('installed!'); event.waitUntil(self.skipWaiting()); // 让新SW立即激活 }); self.addEventListener('activate', function(event) { console.log('activated!'); event.waitUntil(self.clients.claim()); // 接管所有打开的页面 }); self.addEventListener('message', function(event) { // 保留原有消息处理逻辑 }); // 新增:处理推送事件,确保只显示一条通知 self.addEventListener('push', function(event) { const payload = event.data ? event.data.json() : {}; const notificationOptions = { body: payload.body || '您关注的网站发布了新文章', icon: payload.icon || '/wp-content/plugins/your-plugin/icon.png', // 替换为你的插件图标路径 tag: 'new-post-notification', // 用tag确保同类型通知只会显示一条 data: { url: payload.url || self.location.origin // 强制携带跳转链接,兜底为官网 } }; event.waitUntil( // 先关闭已有同tag的通知,再显示新的 self.registration.getNotifications({tag: 'new-post-notification'}) .then(notifications => { notifications.forEach(n => n.close()); return self.registration.showNotification(payload.title || '新文章通知', notificationOptions); }) ); }); // 新增:处理通知点击,确保跳转正确链接 self.addEventListener('notificationclick', function(event) { event.notification.close(); // 打开指定链接,没有的话打开官网 event.waitUntil( clients.openWindow(event.notification.data.url) ); });
2. 优化Service Worker注册逻辑
在generate-token.js中,避免不必要的重复注册和强制更新,只在未注册时才执行注册:
// 替换原有的SW注册代码块 if ('serviceWorker' in navigator) { var myId = obj.messagingSenderId; const swUrl = `${notifyonnewpost.message_sw_path}?messagingSenderId=${myId}¬ifyappjs=${notifyonnewpost.notify_app_path}¬ifymsgjs=${notifyonnewpost.notify_msg_path}`; // 先检查是否已注册该SW navigator.serviceWorker.getRegistration(swUrl) .then(existingReg => { if (!existingReg) { // 未注册时才进行注册操作 return navigator.serviceWorker.register(swUrl); } return existingReg; }) .then(reg => { console.log(`SW registration succeeded. Scope is ${reg.scope}`); messaging.useServiceWorker(reg); // 移除强制更新:reg.update(),除非你确定需要强制用户更新SW,否则不要频繁调用 }) .catch(err => { console.error(`SW registration failed with error ${err}`); }); }
3. 确保后端推送Payload携带正确链接
在WordPress端的推送触发代码中,确保每次发送的推送数据都包含url字段,指向对应的文章页面。比如后端构造的JSON应该是:
{ "title": "你的新文章标题", "body": "文章的简短摘要", "url": "https://your-wordpress-site.com/your-new-post/", "icon": "https://your-wordpress-site.com/wp-content/plugins/your-plugin/assets/notification-icon.png" }
4. 检查后端推送逻辑是否重复触发
确认WordPress中发布文章的钩子(比如publish_post)是否被多次绑定,或者是否存在异步逻辑导致推送请求被发送多次,这也是造成多条通知的常见原因。
验证方法
- 让测试用户清除浏览器的Service Worker和本地存储,重新订阅
- 发布一篇测试文章,检查通知是否只出现一次,且点击能正确跳转到文章页面
- 在不同浏览器(Chrome、Firefox)和设备上测试,确保问题不再复现
内容的提问来源于stack exchange,提问作者raju_odi

