You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby on Rails应用FCM前端JS推送问题:获Token成功但收不到通知

排查FCM Web推送无法接收的问题(Ruby on Rails + RPUSH + Service Worker)

我之前也踩过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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:10:26