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

清除站点数据后Firebase Cloud Message无法获取Token的问题

问题描述

使用Firebase + Vue 3实现通知功能,正常运行无异常,但清除站点数据(clear-site-data)后,首次启动应用无法获取通知Token,重新加载页面可解决该问题。

操作步骤

  • 首次启动应用(运行正常)
  • 打开控制台,进入Application面板
  • 点击Storage后选择Clear Site Data
  • 重新加载页面,触发错误
  • 再次刷新页面,问题解决

错误信息

An error occurred while retrieving token. DOMException: Failed to execute 'subscribe' on 'PushManager': Subscription failed - no active Service Worker

相关代码

firebase-messaging-sw.js

importScripts('https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js')
importScripts('https://www.gstatic.com/firebasejs/8.10.0/firebase-messaging.js')
firebase.initializeApp({...})

const messaging = firebase.messaging();

messaging.onBackgroundMessage((payload) => {
  console.log(
    '[firebase-messaging-sw.js] Received background message ',
    payload
  );
  // Customize notification here
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
    body: payload.notification.body,
    icon: payload.notification.image
  };

  self.registration.showNotification(notificationTitle, notificationOptions);
});

Vue组件代码

const approvedNotification = async () => {
  let permission = await Notification.requestPermission();
  if (permission === "granted") {
    getToken(messaging, { vapidKey: '...' }).then((currentToken) => {
      if (currentToken) {
        token.value = currentToken
        console.log('token:', currentToken)
        // Send the token to your server and update the UI if necessary
        // ...
      } else {
        // Show permission request UI
        console.log('No registration token available. Request permission to generate one.');
        // ...
      }
    }).catch((err) => {
      console.log('An error occurred while retrieving token. ', err);
      // ...
    });
  } else {
    // Handle denied permission
  }
}

onMounted(() => {
  approvedNotification()
})

尝试将Firebase版本从8.10升级至新版本后,出现获取Token的错误,询问是否需要重写firebase-messaging-sw.js。


问题原因与解决方案

问题原因

清除站点数据后,浏览器会删除已注册的Service Worker。首次加载页面时,Vue的onMounted钩子会立即触发approvedNotification去获取Token,但此时Service Worker还处于注册/激活的异步过程中,尚未完全激活,导致PushManager.subscribe调用失败。第二次刷新时,Service Worker已经完成激活,因此能正常获取Token。

针对Firebase 8.x版本的修复

在调用getToken之前,确保Service Worker已经注册并激活。修改Vue组件代码,先等待Service Worker激活完成再执行Token获取逻辑:

// 封装等待Service Worker激活的函数
const waitForServiceWorkerActivation = async () => {
  if ('serviceWorker' in navigator) {
    const registration = await navigator.serviceWorker.register('/firebase-messaging-sw.js');
    // 若Service Worker已激活,直接返回
    if (registration.active) {
      return registration;
    }
    // 等待Service Worker完成激活
    return new Promise((resolve) => {
      const updateListener = () => {
        registration.removeEventListener('updatefound', updateListener);
        registration.installing.addEventListener('statechange', () => {
          if (registration.installing.state === 'activated') {
            resolve(registration);
          }
        });
      };
      registration.addEventListener('updatefound', updateListener);
    });
  }
  throw new Error('Service Worker is not supported');
}

const approvedNotification = async () => {
  let permission = await Notification.requestPermission();
  if (permission === "granted") {
    try {
      // 先等待Service Worker激活
      await waitForServiceWorkerActivation();
      const currentToken = await getToken(messaging, { vapidKey: '...' });
      if (currentToken) {
        token.value = currentToken
        console.log('token:', currentToken)
        // 后续业务逻辑...
      } else {
        console.log('No registration token available. Request permission to generate one.');
      }
    } catch (err) {
      console.log('An error occurred while retrieving token. ', err);
    }
  } else {
    // 处理权限拒绝逻辑
  }
}

onMounted(() => {
  approvedNotification()
})

升级到Firebase新版本(v9+模块化版本)的适配

Firebase v9+采用模块化架构,firebase-messaging-sw.js需要重写,同时前端代码也要调整为模块化导入方式:

重写后的firebase-messaging-sw.js

import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.23.0/firebase-app.js';
import { getMessaging, onBackgroundMessage } from 'https://www.gstatic.com/firebasejs/9.23.0/firebase-messaging-sw.js';

const firebaseApp = initializeApp({
  // 你的Firebase配置信息
});

const messaging = getMessaging(firebaseApp);

onBackgroundMessage(messaging, (payload) => {
  console.log('[firebase-messaging-sw.js] Received background message ', payload);
  const notificationTitle = payload.notification.title;
  const notificationOptions = {
    body: payload.notification.body,
    icon: payload.notification.image
  };

  self.registration.showNotification(notificationTitle, notificationOptions);
});

Vue组件代码调整(v9+模块化)

import { initializeApp } from 'firebase/app';
import { getMessaging, getToken } from 'firebase/messaging';

// 初始化Firebase应用
const firebaseApp = initializeApp({
  // 你的Firebase配置信息
});
const messaging = getMessaging(firebaseApp);

const waitForServiceWorkerActivation = async () => {
  if ('serviceWorker' in navigator) {
    const registration = await navigator.serviceWorker.register('/firebase-messaging-sw.js');
    if (registration.active) {
      return registration;
    }
    return new Promise((resolve) => {
      const updateListener = () => {
        registration.removeEventListener('updatefound', updateListener);
        registration.installing.addEventListener('statechange', () => {
          if (registration.installing.state === 'activated') {
            resolve(registration);
          }
        });
      };
      registration.addEventListener('updatefound', updateListener);
    });
  }
  throw new Error('Service Worker is not supported');
}

const approvedNotification = async () => {
  let permission = await Notification.requestPermission();
  if (permission === "granted") {
    try {
      await waitForServiceWorkerActivation();
      const currentToken = await getToken(messaging, { 
        vapidKey: '你的VAPID密钥' 
      });
      if (currentToken) {
        token.value = currentToken
        console.log('token:', currentToken)
        // 后续业务逻辑...
      } else {
        console.log('No registration token available. Request permission to generate one.');
      }
    } catch (err) {
      console.log('An error occurred while retrieving token. ', err);
    }
  } else {
    // 处理权限拒绝逻辑
  }
}

onMounted(() => {
  approvedNotification()
})

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 09:33:26