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

Firebase Cloud Function内部服务器错误排查与FCM通知修复

排查Firebase Cloud Function触发FCM通知时的Internal Server Error问题

以下是针对你代码中导致Internal Server Error的问题排查及修复方案:

核心问题点及修复

  • 函数定义作用域错误:sendNotification函数定义在主函数的try/catch块之后,虽然JavaScript函数声明会提升,但块级作用域内的函数调用存在风险。将其移至主函数外部,确保调用时已正确定义。

  • Axios请求未异步等待:axios.post调用未添加await,导致直接访问response.data时,response仍是未resolved的Promise,触发未处理错误。需添加await等待请求完成。

  • 空tokens场景未返回响应:当没有符合条件的tokens时直接return,未向客户端返回任何响应,导致请求超时触发500错误。需补充响应返回逻辑。

  • 错误处理不规范:

    • sendNotification的catch块仅打印错误,未将错误传递给主函数,导致主函数无法感知通知发送失败;
    • 主函数catch中res.send传入多个参数,不符合Express响应规则,应合并为单个响应内容。
  • 混用Cloud Functions v1和v2 API:代码同时导入v2的setGlobalOptions和v1的functions.https.onRequest,可能引发兼容性问题。统一使用v2 API(推荐)或完全使用v1。

  • 手动调用FCM API不如Admin SDK便捷安全:已初始化Firebase Admin SDK,直接使用admin.messaging()发送通知,无需手动配置Authorization头,SDK会自动处理认证和错误。

修复后的完整代码

const { setGlobalOptions, onRequest } = require("firebase-functions/v2/https");
const logger = require("firebase-functions/logger");
const admin = require('firebase-admin');

// 全局配置:设置函数最大实例数
setGlobalOptions({ maxInstances: 10 });

// 初始化Firebase Admin SDK
admin.initializeApp();

// 定义通知发送函数(独立作用域)
const sendNotification = async (tokens, notification) => {
    try {
        logger.log('准备发送通知的Token列表:', tokens);
        // 使用Admin SDK发送批量FCM通知
        const response = await admin.messaging().sendMulticast({
            tokens: tokens,
            notification: notification
        });
        logger.log('FCM通知发送响应:', response);
        return response;
    } catch (error) {
        logger.error('发送通知失败:', error);
        throw error; // 抛出错误交由主函数统一处理
    }
};

// 主Cloud Function(使用v2版本的onRequest)
exports.readRealtimeDatabase = onRequest(async (req, res) => {
    try {
        const db = admin.database();
        const dataRef = db.ref('/usersToken');
        const snapshot = await dataRef.once('value');
        const userTokensData = snapshot.val();

        // 处理数据库无数据的情况
        if (!userTokensData) {
            return res.status(200).json({ message: '未找到用户Token数据' });
        }

        const userTokenEntries = Object.values(userTokensData);
        const expiredTokens = [];
        const currentDate = new Date();

        // 筛选出已到期的Token
        userTokenEntries.forEach(entry => {
            logger.log('处理用户Token条目:', entry);
            const expireDate = new Date(entry.timestamp);
            if (expireDate < currentDate) {
                expiredTokens.push(entry.fcmToken);
            }
        });

        // 无到期Token时返回响应
        if (!expiredTokens.length) {
            return res.status(200).json({ message: '没有需要通知的到期用户' });
        }

        // 发送通知并获取响应
        const notificationResult = await sendNotification(expiredTokens, {
            title: "开始新的挖矿会话",
            body: "你的收益在等待,立即开始挖矿吧。"
        });

        // 返回成功响应
        res.status(200).json({
            message: '通知发送成功',
            fcmResult: notificationResult
        });
    } catch (error) {
        logger.error('函数执行出错:', error);
        // 返回结构化错误响应
        res.status(500).json({
            error: '内部服务器错误',
            details: error.message
        });
    }
});

额外优化说明

  • 使用Firebase官方logger替代console.log,符合Cloud Functions的日志管理规范;
  • 所有异步操作添加await,确保流程按顺序执行;
  • 对数据库空数据、无到期Token等边界场景添加明确响应,避免请求超时;
  • 使用Admin SDK的sendMulticast方法,专门用于批量发送FCM通知,比手动调用API更可靠;
  • 错误处理统一抛出并返回结构化JSON,便于后续调试和前端处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 04:55:58