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

Firebase Functions无法推送通知:token输出为undefined问题排查

解决Firebase Functions获取设备Token为undefined的问题

看起来你在这里踩了一个很常见的坑——你的函数监听的是/User这个根节点,但这个节点大概率是多个用户对象的集合,而不是单个用户的数据,所以直接访问notificationSnapshot.token自然拿不到值。

问题根源:数据结构不匹配

你可以仔细看一下console.info(notificationSnapshot)的输出内容,它应该是类似这样的层级结构(假设你的Realtime Database存储了多个用户):

{
  "user_abc123": {
    "token": "fcm_token_xxx",
    "name": "张三",
    "surname": "张"
  },
  "user_def456": {
    "token": "fcm_token_yyy",
    "name": "李四",
    "surname": "李"
  }
}

这个顶层对象本身并没有token属性,token是每个子用户对象的专属属性,所以notificationSnapshot.token返回undefined完全合理。

两种解决方案,根据你的需求选择

方案1:给所有注册用户推送通知

如果你的目标是当/User节点有变化时,给所有用户批量发通知,那需要遍历这个用户集合里的每一个用户,逐个获取Token并发起推送:

// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();

exports.sendSampleNotification = functions.database.ref('/User')
 .onWrite((change, context) => {
   const usersCollection = change.after.val(); // 获取所有用户的集合
   if (!usersCollection) {
     console.log("No users found in /User node");
     return null;
   }

   // 用Promise数组管理所有推送请求,确保函数等待所有操作完成
   const pushPromises = [];
   
   // 遍历每个用户
   for (const userId in usersCollection) {
     const userData = usersCollection[userId];
     const userToken = userData.token;

     // 跳过没有Token的用户,避免无效请求
     if (!userToken) {
       console.log(`User ${userId} has no token, skipping`);
       continue;
     }

     const message = {
       notification: {
         title: 'test title',
         body: 'test message'
       },
       token: userToken
     };

     // 将推送请求加入Promise数组
     const pushPromise = admin.messaging().send(message)
       .then((response) => console.log(`Message sent to ${userId}:`, response))
       .catch((error) => console.log(`Error sending to ${userId}:`, error));
     
     pushPromises.push(pushPromise);
   }

   // 等待所有推送完成,返回Promise让函数正常结束
   return Promise.all(pushPromises);
 });

方案2:单个用户更新时推送通知

如果你的需求是当某个用户的数据更新时,只给这个用户发通知,那应该把监听路径改成/User/{userId}(通过通配符匹配单个用户节点),这样change.after.val()就是单个用户的完整对象,直接取token就没问题了:

// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();

exports.sendSampleNotification = functions.database.ref('/User/{userId}')
 .onWrite((change, context) => {
   const userData = change.after.val(); // 获取单个用户的数据
   const userToken = userData.token;
   const userId = context.params.userId;

   if (!userToken) {
     console.log(`User ${userId} has no token, aborting push`);
     return null;
   }

   const message = {
     notification: {
       title: 'test title',
       body: 'test message'
     },
     token: userToken
   };

   // 返回推送的Promise,确保函数等待异步操作完成
   return admin.messaging().send(message)
     .then((response) => {
       console.log("Message sent successfully:", response);
       return response;
     })
     .catch((error) => {
       console.log("Error sending message: ", error);
       throw error; // 抛出错误让Firebase记录失败状态
     });
 });

额外注意事项

  • 必须返回Promise:Cloud Functions需要知道异步操作什么时候完成,所以一定要返回推送相关的Promise,否则函数会在推送完成前就终止,导致推送失败。
  • 检查Token有效性:一定要判断token是否存在,避免因为某个用户没有Token导致整个推送流程出错。
  • 查看数据结构:如果还是不确定,可以用console.info(JSON.stringify(notificationSnapshot, null, 2))打印格式化后的数据集,这样能更清晰地看到数据的层级结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:08:17