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

基于Vite的React应用中FCM Token失效问题求助

问题分析与解决方案

核心问题

你的代码仅在组件初始化时获取一次FCM Token,但FCM Token会在多种场景下自动刷新(如服务 worker 更新、浏览器存储变更、设备信息改动),而你未监听Token刷新事件,导致后端保存的旧Token失效后无法自动更新,最终出现「设备不存在」的错误。同时主应用用Firebase SDK v9、服务工作线程用v8的版本差异,可能引发隐性兼容性问题,加剧Token刷新异常。


具体解决方案

1. 监听Token刷新事件,自动同步后端存储

在Notification.jsx中添加Token刷新监听逻辑,当Token更新时自动同步到本地存储和后端:

修改后的Notification.jsx关键代码:

import { useEffect } from "react";
import { messaging } from "../firebase";
import { getToken, onMessage, onTokenRefresh } from "firebase/messaging"; // 引入刷新监听方法
import api from "../axiosInstance";
import { saveFcmToken, getFcmToken } from "../utils/storage"; // 新增读取本地Token方法

function Notification() {
  useEffect(() => {
    // 封装Token同步逻辑,避免重复请求
    const syncToken = async (newToken) => {
      const existingToken = await getFcmToken();
      if (newToken !== existingToken) {
        await saveFcmToken(newToken);
        await api.post("/save-token", { fcmToken: newToken });
        console.log("Token updated successfully:", newToken);
      }
    };

    const requestPermission = async () => {
      try {
        const registration = await navigator.serviceWorker.ready;
        const token = await getToken(messaging, {
          vapidKey: 'YOUR_VAPID_KEY',
          serviceWorkerRegistration: registration,
        });

        if (token) {
          await syncToken(token);
        }
      } catch (err) {
        console.error("Error getting token: ", err);
      }
    };

    // 监听Token自动刷新
    const unsubscribeRefresh = onTokenRefresh(async () => {
      try {
        const registration = await navigator.serviceWorker.ready;
        const newToken = await getToken(messaging, {
          vapidKey: 'YOUR_VAPID_KEY',
          serviceWorkerRegistration: registration,
        });
        if (newToken) {
          await syncToken(newToken);
        }
      } catch (err) {
        console.error("Error refreshing token: ", err);
      }
    });

    // 监听前台消息
    const unsubscribeMessage = onMessage(messaging, (payload) => {
      console.log("Message received.", payload);
    });

    // 监听通知权限变化,重新授权后自动获取Token
    const handlePermissionChange = () => {
      if (Notification.permission === "granted") {
        requestPermission();
      }
    };
    Notification.requestPermission().then(handlePermissionChange);
    navigator.permissions.query({ name: "notifications" }).then(permissionStatus => {
      permissionStatus.onchange = handlePermissionChange;
    });

    requestPermission();

    // 清理所有订阅
    return () => {
      unsubscribeRefresh();
      unsubscribeMessage();
    };
  }, []);

  return null;
}

export default Notification;

2. 统一Firebase SDK版本

将服务工作线程的SDK升级到v9,消除版本差异导致的兼容性问题:

修改后的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');

firebase.initializeApp({
  apiKey: "YOUR_API_KEY",
  authDomain: "your-app.firebaseapp.com",
  projectId: "your-app",
  storageBucket: "your-app.appspot.com",
  messagingSenderId: "YOUR_SENDER_ID",
  appId: "YOUR_APP_ID",
  measurementId: "YOUR_MEASUREMENT_ID"
});

const messaging = firebase.messaging();

messaging.onBackgroundMessage((payload) => {
  console.log("Received background message", payload);
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
    body: payload.notification.body,
    icon: 'your-icon.png', 
  };
  self.registration.showNotification(notificationTitle, notificationOptions);
});

3. 后端补充Token失效处理

在后端发送推送时,捕获「设备不存在」的错误,自动从数据库中删除失效Token,避免后续重复无效请求。


关键说明

  • FCM Token刷新由系统自动触发,必须通过onTokenRefresh监听并同步到后端;
  • SDK版本不一致会导致服务 worker 无法正确接收刷新事件,统一版本是必要操作;
  • 监听通知权限变化,确保用户重新授权后能自动获取新Token。

内容的提问来源于stack exchange,提问作者rave

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 06:05:55