PHP服务器与React客户端通过FCM实现Pub/Sub的消息接收问题
排查React前端无法接收FCM消息的解决方案
1. 先理清SDK定位,别搞混概念
FCM的Admin SDK是给服务端(比如你的PHP服务器)用的,前端React项目本来就不该用Admin SDK,你可能误解了文档内容。前端应该用Firebase Web SDK里的Messaging模块,除非你的React版本极端老旧(比如低于16.8),否则基本不会有版本兼容问题。
2. 前端基础配置检查
- 确认已正确初始化Firebase:
import { initializeApp } from "firebase/app"; import { getMessaging } from "firebase/messaging"; const firebaseConfig = { // 从Firebase控制台获取的项目配置 }; const app = initializeApp(firebaseConfig); const messaging = getMessaging(app); - 确认已获取有效FCM令牌(token)并传给PHP服务器:
VAPID密钥需从Firebase控制台「Cloud Messaging」页面的Web配置项中获取。import { getToken } from "firebase/messaging"; const getFCMToken = async () => { try { const token = await getToken(messaging, { vapidKey: "你的VAPID密钥" }); // 将token传给PHP服务器存储,用于后续推送 console.log("FCM Token:", token); } catch (err) { console.error("获取token失败:", err); } };
3. 消息接收逻辑检查
前端接收消息分前台和后台/离线两种场景,需分别配置:
前台消息接收
当React应用处于前台时,通过onMessage监听:
import { onMessage } from "firebase/messaging"; onMessage(messaging, (payload) => { console.log("收到前台消息:", payload); // 这里可自定义消息展示逻辑,比如弹窗、更新页面内容 });
后台/离线消息接收
这种场景需要配置Service Worker:
- 在项目public目录下创建
firebase-messaging-sw.js,内容如下:importScripts("https://www.gstatic.com/firebasejs/9.23.0/firebase-app-compat.js"); importScripts("https://www.gstatic.com/firebasejs/9.23.0/firebase-messaging-compat.js"); const firebaseConfig = { // 你的项目配置 }; firebase.initializeApp(firebaseConfig); const messaging = firebase.messaging(); messaging.onBackgroundMessage((payload) => { console.log("收到后台消息:", payload); // 自定义通知展示 const notificationTitle = payload.notification.title; const notificationOptions = { body: payload.notification.body, icon: "/你的通知图标路径.png" }; self.registration.showNotification(notificationTitle, notificationOptions); }); - 在初始化Messaging时注册该Service Worker:
navigator.serviceWorker.register("/firebase-messaging-sw.js") .then((registration) => { messaging.useServiceWorker(registration); });
4. PHP服务器推送格式检查
FCM推送分通知消息和数据消息,格式错误会导致前端无法接收:
- 确保PHP推送的消息包含正确的
to字段(前端的FCM token),且使用Firebase控制台的「服务器密钥」而非Web的VAPID密钥。 - 示例PHP推送代码:
$url = 'https://fcm.googleapis.com/fcm/send'; $headers = [ 'Authorization: key=你的FCM服务器密钥', 'Content-Type: application/json' ]; $payload = [ 'to' => '前端的FCM token', 'notification' => [ 'title' => '测试推送', 'body' => '这是一条测试消息' ], 'data' => [ 'customData' => '自定义内容' ] ]; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); $result = curl_exec($ch); curl_close($ch);
5. 通知权限检查
前端必须获得用户的通知权限才能接收消息:
import { requestPermission } from "firebase/messaging"; const requestNotificationPermission = async () => { try { const permission = await requestPermission(); if (permission === "granted") { console.log("通知权限已授权"); await getFCMToken(); } } catch (err) { console.error("请求权限失败:", err); } };
6. 兼容旧React版本的方案
如果你的React版本确实过低(比如低于16.8),可以改用Firebase v8.x版本的SDK,它采用命名空间语法,无需依赖React Hooks,兼容性更好:
import firebase from "firebase/app"; import "firebase/messaging"; const firebaseConfig = { /* 项目配置 */ }; firebase.initializeApp(firebaseConfig); const messaging = firebase.messaging(); // 获取token messaging.getToken({ vapidKey: "你的VAPID密钥" }).then(token => { console.log(token); }); // 监听前台消息 messaging.onMessage(payload => { console.log(payload); });
内容的提问来源于stack exchange,提问作者Afif Malghani
相关产品推荐
相关产品推荐

