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

Node.js+Express下FCM推送后存储通知到MySQL失效问题

问题场景
  • 基于Node.js + Express开发服务端,对接Firebase Cloud Messaging向App用户推送通知
  • 业务逻辑要求:推送发送完成后,将通知ID、标题、内容存入MySQL的notifications表
  • 故障表现:插入逻辑不执行,回调参数rows为undefined,数据库无对应新增数据
  • 原有问题代码:
const message_notification = {
    notification: {
        title: "notification_title",
        body: "notification_body"
    }
};

const notification_options = {
    priority: "high",
    timeToLive: 60 * 60 * 24
};


admin.messaging().sendToDevice(device_token, message_notification, notification_options)
    .then( response => {      
       
        //doesn't work
        mySqlConnection.query(`insert into notifications (notification_id, body, title) values
        (?,?,?)`, [response.multicastId, message_notification.notification.body, message_notification.notification.title], (err,rows)=>
        {
            try
            {
                console.log(rows);
            }

            catch(err)
            {
                console.log(err)
            }
        });
        })
故障根因
  1. MySQL回调逻辑写反:mysql驱动的查询回调中,错误参数err永远是第一个参数,只要SQL执行失败,err会携带具体错误详情,此时rows必然为undefined。你的代码既没有优先判断err,还用try/catch包裹同步的console.log逻辑,根本捕获不到SQL执行的异步错误,完全看不到真实报错原因。常见的SQL执行失败原因包括:
    • 数据库连接断开、连接权限不足
    • notifications表不存在、字段名/字段类型不匹配
    • notification_id字段主键冲突
    • SQL语法错误
  2. Promise链异常被吞:你没有给admin.messaging().sendToDevice的Promise加.catch()分支,推送阶段的错误(比如device_token无效、Firebase SDK初始化失败、网络超时、参数不合法)会被完全静默,没有任何日志输出。
  3. 缺少推送结果校验:sendToDevice支持批量推送,即使请求整体成功返回response,也可能存在部分/全部token推送失败的情况,直接拿multicastId写库可能产生无效数据。
修复后可运行代码
const message_notification = {
    notification: {
        title: "notification_title",
        body: "notification_body"
    }
};

const notification_options = {
    priority: "high",
    timeToLive: 60 * 60 * 24
};

admin.messaging().sendToDevice(device_token, message_notification, notification_options)
    .then(response => {
        // 先校验推送结果,记录失败的token
        if (response.failureCount > 0) {
            const failedList = [];
            response.responses.forEach((item, index) => {
                if (!item.success) {
                    failedList.push({
                        token: Array.isArray(device_token) ? device_token[index] : device_token,
                        errorMsg: item.error?.message || '未知推送错误'
                    });
                }
            });
            console.error('存在推送失败的设备:', failedList);
        }

        // 执行入库操作,优先处理错误
        mySqlConnection.query(
            `INSERT INTO notifications (notification_id, body, title) VALUES (?,?,?)`,
            [response.multicastId, message_notification.notification.body, message_notification.notification.title],
            (err, rows) => {
                if (err) {
                    console.error('通知入库失败,错误详情:', err);
                    return;
                }
                console.log('通知入库成功,插入返回结果:', rows);
            }
        );
    })
    .catch(err => {
        // 捕获推送阶段的全局异常
        console.error('Firebase推送请求失败:', err);
    });
修复要点
  • 所有MySQL查询回调必须先判断err是否存在,存在则直接打印错误、终止后续逻辑,不要直接操作rows/results参数
  • 异步Promise链必须加catch分支,不要静默吞掉任何阶段的错误,否则排查问题时没有任何日志依据
  • 去掉回调里无意义的try/catch:mysql驱动已经把异步错误通过第一个err参数返回,外层包裹try/catch只能捕获回调内同步代码的报错,捕获不到SQL执行的异步错误
  • 批量推送场景必须校验failureCount,及时清理无效的device_token,减少无效推送请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 01:01:10