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

如何规范编写函数?请求修正Firebase云函数FCM令牌获取代码

解决FCM发送时"Registration token(s) provided to sendToDevice() must be a non-empty string..."错误

你的代码存在语法和逻辑层面的多处错误,直接导致FCM令牌获取失败,以下是修正后的完整代码:

const functions = require("firebase-functions");
const admin = require('firebase-admin');

admin.initializeApp(); // 现代Firebase版本无需手动传入config,SDK会自动完成初始化

exports.orderCompleteTrigger = functions.firestore.document('Orders/{orderId}').onWrite(async (change, context) => {
    // 订单删除时直接终止函数,避免无效触发
    if (!change.after.exists) return null;
    
    const orderId = context.params.orderId;
    const orderData = change.after.data();
    
    // 从当前订单文档中直接提取fcmToken(假设令牌存储在订单文档的fcmToken字段中)
    const fcmToken = orderData.fcmToken;
    
    // 提前校验令牌有效性
    if (!fcmToken || typeof fcmToken !== 'string' || fcmToken.trim() === '') {
        console.log('无效或空的FCM令牌:', fcmToken);
        return null;
    }

    // 构造纯静态的FCM通知payload
    const payload = {
        notification: {
            title: "订单已完成",
            body: "感谢您的惠顾,期待再次为您服务!"
        }
    };

    try {
        // 发送FCM通知
        const response = await admin.messaging().sendToDevice(fcmToken, payload);
        console.log('通知发送成功:', response);
        
        // 可选:处理发送失败的无效令牌
        const invalidTokens = [];
        response.results.forEach((result) => {
            const error = result.error;
            if (error) {
                console.error('令牌发送失败:', fcmToken, error);
                // 标记无效令牌,后续可从数据库移除
                if (error.code === 'messaging/invalid-registration-token' || 
                    error.code === 'messaging/registration-token-not-registered') {
                    invalidTokens.push(fcmToken);
                }
            }
        });
        
        // 批量移除数据库中的无效令牌
        if (invalidTokens.length > 0) {
            await change.after.ref.update({ fcmToken: admin.firestore.FieldValue.delete() });
        }
        return null;
    } catch (error) {
        console.error('发送通知时发生异常:', error);
        return null;
    }
});

关键修正点说明:

  • 移除错误嵌套逻辑:你之前将Firestore异步查询直接写在payload.notification对象中,这是严重的语法错误——payload必须是纯静态的通知内容,异步操作需独立于payload存在。
  • 高效获取令牌:无需重新查询订单文档,直接通过change.after.data()获取当前订单的最新数据,既避免路径错误,又提升执行效率。
  • 前置令牌校验:在发送通知前先检查令牌是否为非空字符串,从根源避免FCM的空令牌报错。
  • 简化异步流程:使用async/await替代嵌套的then/catch,代码可读性更强,同时确保异步操作能完整执行。
  • 规范Admin初始化:现代Firebase版本中,admin.initializeApp()无需传入额外参数,SDK会自动读取环境配置完成初始化。
  • 完善错误处理:捕获发送通知时的异常,并添加无效令牌的处理逻辑,提升代码健壮性。

额外注意事项:

  1. 确认Orders集合中的文档确实包含fcmToken字段,且字段值为有效的FCM设备令牌字符串。
  2. 云函数必须返回Promise或具体值,否则可能导致函数提前终止,异步操作无法完成。
  3. 若需向多个设备发送通知,只需将fcmToken替换为令牌数组即可,sendToDevice支持传入数组参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 16:10:20