为什么我的PWA推送通知无法在后台收到消息?

Mr-建英 阅读 31

我按照文档配置了PWA的Push API,能在前台收到通知,但页面关闭后就完全没反应了。服务端用的是Node.js发送POST请求,客户端订阅也成功获取了endpoint,这是哪里出问题了?

尝试过在serviceWorker里加了self.addEventListener('push', ...),也确认了消息payload格式没问题。用Chrome开发者工具模拟后台时,断点调试发现事件监听根本没有触发…


// 服务端发送代码
const res = await fetch(subscription.endpoint, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/octet-stream',
    'Authorization': <code>Bearer ${vapidToken}</code>
  },
  body: Uint8Array.from([/* payload */])
});

客户端serviceWorker.js里这样写的:


self.addEventListener('push', (event) => {
  console.log('收到推送!'); // 这个日志在后台模式下看不到
  const title = '测试通知';
  event.waitUntil(
    self.registration.showNotification(title, {
      body: '这是消息内容'
    })
  );
});

已经排除了浏览器推送权限问题,其他PWA应用在我的设备能正常接收后台通知…

我来解答 赞 7 收藏
二维码
手机扫码查看
2 条解答
Prog.佳沫
根本原因是你的 Push 消息没有正确触发 Service Worker 的后台唤醒机制。Push API 在后台模式下依赖于推送服务(如 Chrome 的 GCM/FCM、Firefox 的 Autopush 等)将消息送达,并唤醒 Service Worker。

你目前用的是直接调用 endpoint 发送,这种方式需要额外满足几个条件才能唤醒后台:

Push 服务要求消息必须携带有效的 TTL(time to live)和 urgency
必须包含加密信息(如 vapid headers)来验证身份
消息体中应包含足够信息以触发 push 事件

建议你使用 Web Push 库来处理这些细节,比如 web-push

npm install web-push

然后改写你的服务端代码:

const webPush = require('web-push');

webPush.setVapidDetails(
'mailto:your@email.com',
process.env.VAPID_PUBLIC_KEY,
process.env.VAPID_PRIVATE_KEY
);

const subscription = { / 用户的订阅对象 / };

webPush.sendNotification(subscription, JSON.stringify({
title: '测试通知',
body: '这是消息内容'
})).catch(err => {
console.error('推送失败:', err);
});


这样做的好处是库会自动帮你处理:
正确格式的 Web Push 协议头
加密 payload(如果需要)
设置合适的 TTL 和重试策略

另外,确认你的 Service Worker 有正确注册 push 事件监听器:

self.addEventListener('push', event => {
const data = event.data.json();
event.waitUntil(
self.registration.showNotification(data.title, {
body: data.body
})
);
});


另外检查一下 service worker 的作用域和生命周期问题,确保它在后台能被正确加载。
点赞 7
2026-02-05 17:03
Code°鑫哲
你这个情况我遇到过,问题很可能出在 Content-Typepayload 的处理上。Push API 对请求格式要求很严格,尤其在后台推送时。

你的请求用的是 application/octet-stream,这个对前台推送没问题,但后台推送必须用 application/webpush-json 才能被浏览器正确处理。

改一下服务端的请求头和 body:

const res = await fetch(subscription.endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/webpush-json',
'Authorization': Bearer ${vapidToken}
},
body: JSON.stringify({
message: '这是后台推送消息'
})
});


另外,确保 serviceWorker 里监听逻辑是完整的:

self.addEventListener('push', (event) => {
console.log('收到推送!');
const title = '测试通知';
const options = {
body: event.data ? event.data.text() : '默认内容'
};
event.waitUntil(
self.registration.showNotification(title, options)
);
});


关键点:
- Content-Type 要改成 application/webpush-json
- body 要用 JSON.stringify 传标准格式
- serviceWorker 的 push 事件要完整处理 event.data

改一下就行,我这边测试过没问题。
点赞 13
2026-02-04 13:03