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

Node.js+Express中请求内实现FCM通知入库不生效如何解决

问题根本原因
  • 核心逻辑错误:你在fcm.send的成功回调内部动态声明app.post("/notfs")路由,路由声明仅用于注册接口规则,必须在服务启动阶段完成,不能写在接口请求处理逻辑中。声明该路由后不会自动触发执行,因此数据库写入逻辑从来没有被调用过。
  • 异步逻辑混乱:外层/fcm接口用了async声明,内部fcm.send用回调写法,嵌套逻辑容易遗漏异常捕获,也没有在逻辑处理完后给请求方返回响应。
修复实现

你不需要额外定义POST /notfs接口来存储通知,直接在FCM发送成功后执行数据库写入即可,修复后的完整代码如下:

var FCM = require("fcm-node");
const express = require("express");
const mongoose = require("mongoose");
require("dotenv/config");

const app = express();
app.use(express.json());

// 扩展通知表字段,存储更完整的信息
const notificationSchema = mongoose.Schema({
  title: String,
  body: String,
  targetToken: String,
  sendStatus: { type: String, enum: ['success', 'fail'], default: 'success' },
  fcmMsgId: String,
  createTime: { type: Date, default: Date.now }
});
const NotificationModel = mongoose.model("Notification", notificationSchema);

// 封装fcm.send为promise,适配async/await写法
function sendFcmPromise(fcm, message) {
  return new Promise((resolve, reject) => {
    fcm.send(message, (err, res) => {
      if (err) return reject(err);
      resolve(res);
    })
  })
}

app.post("/fcm", async (req, res, next) => {
  const { token, title, body } = req.body;
  // 可自行补充参数非空校验逻辑
  let sendResult = null;
  let sendStatus = 'success';
  try {
    const fcm = new FCM(process.env.SERVER_KEY);
    const message = {
      to: token,
      notification: { title, body },
    };
    sendResult = await sendFcmPromise(fcm, message);
  } catch (err) {
    sendStatus = 'fail';
    next(err);
  } finally {
    // 无论发送成功失败都存入数据库,方便排查
    const newNotf = new NotificationModel({
      title,
      body,
      targetToken: token,
      sendStatus,
      fcmMsgId: sendResult?.results[0]?.message_id || null
    });
    await newNotf.save();
  }
  res.json({
    code: 200,
    msg: '通知发送完成',
    data: sendResult
  })
});

app.get("/notfs", async (req, res) => {
  const notfs = await NotificationModel.find().sort({ createTime: -1 });
  res.send(notfs);
});

mongoose
  .connect(process.env.CONNECTION_STRING)
  .then(() => console.log("数据库连接成功"))
  .catch((err) => console.log("数据库连接失败", err));

app.listen(3000, () => console.log("服务启动,监听3000端口"));
优化点说明
  • 用Promise封装回调形式的fcm.send方法,统一用async/await处理异步逻辑,避免回调嵌套
  • 扩展通知表字段,存储通知标题、目标设备token、发送状态、FCM返回的消息ID、发送时间,方便后续排查问题和历史追溯
  • 新增finally逻辑,无论通知发送成功还是失败都写入数据库,完整记录所有请求
  • 补充请求响应返回,调用方可以明确知道请求处理结果
  • 查询历史通知接口新增按时间倒序排序,最新发送的通知排在最前面

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 20:45:07