Ruby on Rails应用FCM前端JS推送问题:获Token成功但收不到通知
我之前也踩过FCM web推送的坑,结合你描述的情况——RPUSH已配置运行、CURL请求返回成功、Service Worker能正常获取Token但就是收不到通知,可以从这几个方向逐一排查:
1. 确认FCM消息Payload格式是否符合Web端要求
FCM对Web推送的Payload有明确格式要求,如果只传data字段,浏览器不会自动展示通知,必须通过Service Worker手动处理。用CURL测试时,要确保Payload包含notification字段(用于自动展示),或者同时包含data+Service Worker的事件监听。
正确的Web推送Payload示例:
{ "to": "你的客户端Token", "notification": { "title": "测试通知", "body": "这是一条来自FCM的推送", "icon": "/assets/notification-icon.png", "click_action": "https://你的域名.com" }, "webpush": { "headers": { "Urgency": "high" } } }
如果你的RPUSH代码只传了data字段,一定要在Service Worker里监听push事件并手动创建通知。
2. 检查Service Worker的Push事件监听是否正确
使用serviceworker-rails后,必须确保Service Worker文件里正确注册了push事件监听器,否则即使收到推送也无法展示。示例代码:
self.addEventListener('push', function(event) { // 解析推送数据 const payload = event.data ? event.data.json() : {}; const notificationTitle = payload.notification?.title || '新通知'; const notificationOptions = { body: payload.notification?.body || '', icon: payload.notification?.icon || '/assets/default-icon.png', data: payload.data || {} // 用于点击通知时传递数据 }; // 等待通知展示完成 event.waitUntil( self.registration.showNotification(notificationTitle, notificationOptions) ); }); // 可选:处理通知点击事件 self.addEventListener('notificationclick', function(event) { event.notification.close(); // 跳转到指定页面 event.waitUntil( clients.openWindow('/notifications') ); });
可以在浏览器开发者工具的Application > Service Workers面板,查看Service Worker是否处于activated状态,有没有报错信息。
3. 验证RPUSH的Web平台配置是否正确
RPUSH支持多平台,要确保你创建的是Webpush类型的App,而不是GCM(旧版Android)类型。Rails初始化配置示例:
# config/initializers/rpush.rb Rpush.configure do |config| config.client = :net_http end # 创建Webpush应用(可在rails console执行) Rpush::Webpush::App.create!( name: 'my_web_app', api_key: '你的FCM服务器密钥', vapid_public_key: '你的VAPID公钥', vapid_private_key: '你的VAPID私钥', vapid_email: '你的邮箱(用于FCM联系)' )
发送推送时,要指定对应的Webpush App:
notification = Rpush::Webpush::Notification.new notification.app = Rpush::Webpush::App.find_by(name: 'my_web_app') notification.device_token = '客户端传递的Token(即subscription.endpoint)' notification.data = { notification: { title: 'RPUSH测试推送', body: '这是一条来自RPUSH的通知' } } notification.save!
如果误用了Rpush::Gcm::App,会导致Web端无法正确接收推送。
4. 检查浏览器的通知权限和运行状态
- 确认用户已授权通知权限:在浏览器控制台执行
Notification.permission,返回granted才是正常状态 - 隐身模式下部分浏览器会阻止推送,建议用普通窗口测试
- 检查浏览器是否把你的域名加入了通知拦截列表
5. 查看FCM推送日志和浏览器控制台
- 登录Firebase控制台,进入
Cloud Messaging > 报告,查看消息是否真的被FCM成功送达(CURL返回成功仅代表请求被FCM接收,不代表已送达客户端) - 在浏览器开发者工具的
Console标签,查看是否有push事件相关的错误信息
6. 确认VAPID密钥是否前后端匹配
如果使用VAPID(Web推送推荐方式),前端获取Token时传入的公钥,必须和RPUSH配置里的VAPID公钥完全一致。前端代码示例:
// 转换VAPID公钥格式 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))); } // 订阅推送 navigator.serviceWorker.ready.then(registration => { const vapidPublicKey = '你的VAPID公钥'; const convertedKey = urlBase64ToUint8Array(vapidPublicKey); return registration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: convertedKey }); }).then(subscription => { // 将subscription.endpoint发送到服务器保存为Token });
如果密钥不匹配,FCM会拒绝推送请求,或者客户端无法接收。
内容的提问来源于stack exchange,提问作者Talha Shoaib

