实现消息实时推送的Push API实战经验与避坑指南
Push API的坑,我踩了不止一个
最近在搞移动端的消息推送功能,用到了Push API。听起来挺简单的一个API,结果折腾了我整整两天。这里记录下我遇到的几个坑和最终解决方案,给同样踩坑的小伙伴一点参考。
第一个坑:用户明明点了允许,却收不到推送
最开始的问题是这样的:用户点击允许通知权限后,服务器也显示推送成功了,但设备就是收不到消息。这里我踩了个大坑,浪费了不少时间。
后来发现是service worker没正确注册。很多人不知道,Push API其实是依赖service worker工作的。即使你拿到了用户授权,如果sw文件路径不对或者没加载成功,消息还是发不过来。
这是我的最终解决方案:
// 注册service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
console.log('Service Worker registered with scope:', registration.scope);
}).catch(function(error) {
console.error('Service Worker registration failed:', error);
});
}
// 请求通知权限
Notification.requestPermission().then(permission => {
if (permission === 'granted') {
console.log('Notification permission granted.');
}
});
注意这里的sw.js一定要放在根目录,因为它的作用域是由其位置决定的。我之前把它放错了位置,导致整个功能都跑不起来。
第二个坑:payload大小限制
这个坑更隐蔽。我在测试环境一切正常,结果上线后发现部分消息接收失败。折腾了半天才发现是payload大小超限了。
根据规范,push message的payload不能超过4KB。但是不同浏览器的实现有差异,比如Chrome就严格限制在4KB以内,而Firefox稍微宽松一些。
解决方法是把重要数据存在服务器端,只传递一个消息ID:
self.addEventListener('push', function(event) {
const data = event.data.json();
const messageId = data.id;
// 从服务器获取完整消息内容
event.waitUntil(
fetch(https://jztheme.com/api/message/${messageId}).then(response => {
return response.json();
}).then(messageData => {
const title = messageData.title;
const options = {
body: messageData.body,
icon: messageData.icon
};
return self.registration.showNotification(title, options);
})
);
});
第三个坑:后台同步问题
还有一个容易忽略的问题是,当应用在后台时,有时候收不到推送。这里需要注意两点:
- 确保manifest.json配置正确
- 使用background sync做补充
我的manifest.json是这么配的:
{
"name": "Push Demo",
"short_name": "PushDemo",
"start_url": "/index.html",
"display": "standalone",
"background_color": "#ffffff",
"gcm_sender_id": "1234567890" // 这里要替换成自己的GCM sender ID
}
一些额外的注意事项
1. 不同浏览器对Push API的支持程度不一样,建议在caniuse上查一下最新支持情况
2. 记得处理各种异常情况,比如网络断开、服务端错误等
3. 在开发过程中,推荐使用navigator.serviceWorker.ready来确保sw已经ready
以上是我踩坑后的总结,虽然现在功能基本跑通了,但感觉还有很多可以优化的地方。如果你有更好的方案欢迎评论区交流。
顺便吐槽一句,这玩意儿调试起来是真的麻烦,尤其是涉及到service worker的时候,刷新缓存什么的特别烦人。不过话说回来,一旦调通了还挺有成就感的。

暂无评论