Web Push通知已接收但无法触发的技术求助
问题:Web Push通知无法触发
我基于webpush做了一个POC验证浏览器推送通知功能,页面有两个按钮分别用于订阅推送和测试通知:
- 订阅流程已完成,日志能确认订阅信息已存储
- 点击测试按钮会向
/notify接口发起POST请求,返回200状态码 - 已生成VAPID密钥对,公钥配置在index.html,私钥配置在server.js
- Chrome能打印出worker中的
console.log内容,但Chrome和Firefox都没实际弹出通知 - 项目本地跑在3000端口,通过Nginx Proxy Manager反向代理到带有效SSL证书的子域名
https://sub.mydomain.com,已启用WebSocket支持 - 浏览器已允许该域名的推送权限,订阅时也成功获取了权限,Firefox开启Service Worker调试也没找到问题
相关代码
server.js
const express = require('express'); const webpush = require('web-push'); const path = require('path'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.json()); // Serve static files from the 'public' directory app.use(express.static(path.join(__dirname, 'public'))); const publicVapidKey = 'my pub key'; const privateVapidKey = 'my priv key'; webpush.setVapidDetails('mailto:noreply@mydomain.com', publicVapidKey, privateVapidKey); let subscriptions = []; app.post('/subscribe', (req, res) => { const subscription = req.body; subscriptions.push(subscription); console.log('subscriptions: ', subscriptions); res.status(201).json({}); }); app.post('/notify', (req, res) => { console.log('hit /notify'); const payload = JSON.stringify({ title: 'New Notification', message: 'You have a new notification!' }); subscriptions.forEach(sub => { webpush.sendNotification(sub, payload).catch(err => { console.error('Error sending notification:', err); }); }); res.status(200).json({}); }); app.use(express.static('public')); app.listen(3000, () => { console.log('Server started on port 3000'); });
worker.js
self.addEventListener('push', event => { console.log('push received'); console.log(event); console.log(event.data); console.log(event.data.json()); const data = event.data.json(); // debugger; self.registration.showNotification(data.title, { body: data.message, icon: '/icon.png' }); // tried this too: //const notification = new Notification(data.title, { // body: data.message, // icon: '/icon.png' //}); });
index.html(核心代码)
// Subscribe for push notifications async function subscribeUser() { const registration = await navigator.serviceWorker.register('/worker.js', { scope: '/' }); const subscription = await registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(publicVapidKey) }); await fetch('/subscribe', { method: 'POST', body: JSON.stringify(subscription), headers: { 'Content-Type': 'application/json' } }); alert('Subscribed successfully!'); } // Send a test notification async function sendNotification() { await fetch('/notify', { method: 'POST' }); } function urlBase64ToUint8Array(base64String) { const padding = '='.repeat((4 - base64String.length % 4) % 4); const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/'); const rawData = window.atob(base64); return Uint8Array.from([...rawData].map((char) => char.charCodeAt(0))); } document.getElementById('subscribe').addEventListener('click', subscribeUser); document.getElementById('notify').addEventListener('click', sendNotification);
排查与修复方案
1. 给Service Worker的推送事件添加waitUntil
Push事件处理需要确保异步操作被event.waitUntil()包裹,否则浏览器可能在通知展示前终止Service Worker。修改worker.js:
self.addEventListener('push', event => { console.log('push received'); const data = event.data.json(); // 用waitUntil包裹异步操作,确保Service Worker存活到通知展示完成 event.waitUntil( self.registration.showNotification(data.title, { body: data.message, icon: '/icon.png' }) ); });
2. 验证VAPID密钥对的正确性
- 确保公钥和私钥是配对生成的,重新生成密钥对可以用web-push提供的命令:
npx web-push generate-vapid-keys - 检查index.html中的
publicVapidKey是否是原始公钥(不要包含额外的引号或空格),转换函数urlBase64ToUint8Array是否正确处理了密钥格式。
3. 检查通知资源与权限细节
- 确认
icon.png存在且可访问,路径/icon.png是否正确,若图标加载失败部分浏览器会静默不显示通知。 - 手动验证浏览器通知功能:在控制台执行
new Notification('测试', {body: '测试通知'}),确认系统和浏览器没有拦截通知。
4. 完善Nginx反向代理配置
确保Nginx Proxy Manager的配置正确传递请求头,添加以下自定义配置:
location / { proxy_pass http://localhost:3000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; # 确保WebSocket支持 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; }
5. 查看完整推送错误日志
在server.js的错误捕获中打印完整错误栈,定位推送服务返回的具体问题:
webpush.sendNotification(sub, payload).catch(err => { console.error('推送错误详情:', err, err.stack); });
常见错误包括VAPID签名无效、订阅信息过期、推送服务返回404/410等。
内容的提问来源于stack exchange,提问作者David Fox
相关产品推荐
相关产品推荐

