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

使用Firebase getToken时提示无活跃Service Worker问题求助

问题:React集成Firebase推送通知,清除存储后首次刷新报错

initializing Firebase Messaging: DOMException: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker

我通过以下代码确认Firebase Service Worker已激活:

const regs = await navigator.serviceWorker.getRegistrations();
console.log("🚀 ~ $$$ ~ requestNotificationPermission ~ regs:", regs)

但仍出现上述错误。我的Firebase配置从后端获取,相关代码如下,求解决思路。

初始化Service Worker的推送通知组件代码

import { useCallback, useEffect } from 'react';
import { useQuery } from '@apollo/client';
import { requestNotificationPermission } from 'app/utils/firebaseUtils';
import { notify } from 'app/utils/notification/notification';
import { initializeApp } from 'firebase/app';
import { getMessaging, onMessage } from 'firebase/messaging';
import { firebaseConfigQuery } from 'graphql/app/pushNotificationQueries';

const PushNotifications = () => {
    const { data }  = useQuery(firebaseConfigQuery);

    const intiFirebaseApp = useCallback(async(config) =>{
        if(!config) return;
        const { vapidKey, ...appConfig } = config;
        const app = initializeApp(appConfig);
                    
        const messaging = getMessaging(app);
                    
        const permission = await requestNotificationPermission(messaging, vapidKey);
            
        if(permission === 'granted') {
            onMessage(messaging, payload => {
                const { topic, payload:message } = payload?.data;
                console.log('🚀 ~ $$$ ~ PushNotifications ~ payload:', payload);
                // 用户登录并订阅通知时无需显示通知
                if(topic === 'subscription') return;
                notify(topic, {body: message});
            });
        }
    },[]);

    const initFirebaseSW = useCallback(async (config) => {
        if ('serviceWorker' in navigator) {
            try{
                const registration = await navigator.serviceWorker.register('/firebase-messaging-sw.js', {
                    scope: '/'
                });
                console.log('Service Worker registered with scope:', registration?.scope);
                await navigator.serviceWorker.ready;
                // await registration?.pushManager?.subscribe({
                //     userVisibleOnly:true,
                // });
                intiFirebaseApp(config);
            }catch(err){
                console.error('Service Worker registration failed:', err);
            }
        }
    }, [intiFirebaseApp]);

    useEffect(()=>{
        const firebaseConfig = data?.affectliSettings?.messaging;
        if(firebaseConfig){
            initFirebaseSW(firebaseConfig);
        }
    },[data, initFirebaseSW]);
     
    return null;
};

export default PushNotifications;

请求通知权限及订阅工具函数代码

export  const requestNotificationPermission = async (messaging, vapidKey) => {
    if (!('Notification' in window)) {
        //eslint-disable-next-line
        console.log('This browser does not support notifications.');
        return Promise.resolve();
    }
    
    // 检查当前权限状态
    let permission = Notification.permission;
    
    // 如果权限是'default',则请求权限
    if (permission === 'default') {
        permission = await Notification.requestPermission();
    }
    
    if (permission === 'granted') {
        const regs = await navigator.serviceWorker.getRegistrations();
        console.log("🚀 ~ $$$ ~ requestNotificationPermission ~ regs:", regs)
        const currentToken = await getToken(messaging, {vapidKey});
        console.log('🚀 ~ $$$ ~ requestNotificationPermission ~ currentToken:', currentToken);
        if(currentToken){
            // 将token发送到服务器
           const res = await subscribeNotifications(currentToken);
           const status = res?.data?.pushNotificationAddToken;
           if(typeof status === 'boolean'){
            if(status){
                 //eslint-disable-next-line
              console.log('$$$  : 推送通知订阅成功');
             }else{
             //eslint-disable-next-line
              console.log('$$$  : 推送通知已订阅');
             }
            }
         }
    } else if (permission === 'denied') {
        // eslint-disable-next-line
        console.log('🚀 ~ requestNotificationPermission ~ permission:', permission);
    }
    return permission;
};

解决思路

  1. 确保Service Worker完全激活后再初始化Firebase Messaging
    虽然调用了await navigator.serviceWorker.ready,但Firebase的getToken可能需要等待Service Worker完成激活的全部步骤。可以修改initFirebaseSW,确认registration处于active状态后再执行初始化:

    await navigator.serviceWorker.ready;
    // 等待Service Worker激活
    if (registration.active) {
        intiFirebaseApp(config);
    } else {
        registration.addEventListener('activate', () => {
            intiFirebaseApp(config);
        });
    }
    
  2. 检查firebase-messaging-sw.js的位置与内容

    • 确保文件放在项目根目录(与index.html同层级),否则注册路径会出错。
    • 文件必须包含Firebase初始化代码,示例:
      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_AUTH_DOMAIN",
        projectId: "YOUR_PROJECT_ID",
        storageBucket: "YOUR_STORAGE_BUCKET",
        messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
        appId: "YOUR_APP_ID"
      });
      
      const messaging = firebase.messaging();
      
      // 处理后台消息
      messaging.onBackgroundMessage(function(payload) {
        console.log('[firebase-messaging-sw.js] Received background message ', payload);
        const notificationTitle = payload.notification.title;
        const notificationOptions = {
          body: payload.notification.body,
          icon: '/firebase-logo.png'
        };
      
        self.registration.showNotification(notificationTitle, notificationOptions);
      });
      
  3. 清除存储后先注销旧Service Worker再重新注册
    清除存储后旧的Service Worker可能处于不稳定状态,可在initFirebaseSW中先注销旧注册:

    // 先注销所有旧的Service Worker
    const registrations = await navigator.serviceWorker.getRegistrations();
    for (let reg of registrations) {
        await reg.unregister();
    }
    // 再注册新的
    const registration = await navigator.serviceWorker.register('/firebase-messaging-sw.js', {
        scope: '/'
    });
    
  4. 显式传入Service Worker注册给getToken
    在requestNotificationPermission中调用getToken时,显式传入当前的Service Worker注册,避免Firebase找不到正确的Worker:

    const registration = await navigator.serviceWorker.ready;
    const currentToken = await getToken(messaging, {
        vapidKey,
        serviceWorkerRegistration: registration
    });
    
  5. 检查浏览器缓存与Service Worker更新策略
    清除存储后浏览器可能缓存旧的Service Worker文件,开发环境可开启强制更新检查,生产环境需设置正确的缓存策略,确保新Worker能被正确加载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 20:27:11