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

Node.js集成Razorpay后端指导:支付捕获与数据存储(Flutter前端)

Razorpay Node.js 后端配置与支付验证实现

核心需求梳理

你需要基于Node.js后端对接Razorpay完成套餐订阅的支付验证、金额捕获,并将支付数据持久化到数据库,前端通过Flutter传递razorpay_id(即支付ID)到后端进行后续处理。

步骤1:确保Razorpay SDK正确安装

先确认已安装官方SDK:

npm install razorpay

步骤2:支付验证与金额捕获逻辑实现

Razorpay的支付流程中,前端完成用户授权后会返回razorpay_payment_id,后端需要通过这个ID:

  1. 查询支付订单的真实状态
  2. 若订单处于authorized状态,执行金额捕获操作(Razorpay默认需手动捕获,除非配置自动捕获)
  3. 验证捕获成功后,再更新用户订阅数据与数据库

修正后的后端路由代码

exports.subscribe_package = catchAsync(async (req, res) => {
  try {
    // 初始化Razorpay实例
    const razorPay = new RazorPay({
      key_id: keys.razorPayKey,
      key_secret: keys.razorPaySecret,
    });

    const { razorpay_id: paymentId } = req.body;
    const userId = req.data.id;
    const packageId = req.params.id;

    // 1. 查询支付订单详情,验证状态合法性
    const paymentDetails = await razorPay.payments.fetch(paymentId);
    
    // 排除未授权、已失败的支付
    if (paymentDetails.status !== 'authorized' && paymentDetails.status !== 'captured') {
      return res.failed(400, "支付未完成或无效", null);
    }

    // 2. 手动捕获未完成的授权金额
    let capturedPayment;
    if (paymentDetails.status === 'authorized') {
      capturedPayment = await razorPay.payments.capture(paymentId, paymentDetails.amount);
    } else {
      capturedPayment = paymentDetails;
    }

    // 3. 保存支付核心数据到数据库
    const savedPayment = await paymentService.savePayment({
      user_id: userId,
      package_id: packageId,
      razorpay_payment_id: capturedPayment.id,
      amount: capturedPayment.amount / 100, // 转换为INR(Razorpay用最小单位paisa)
      currency: capturedPayment.currency,
      status: capturedPayment.status,
      created_at: new Date(capturedPayment.created_at * 1000)
    });

    // 4. 执行原有用户订阅更新逻辑
    const subscription = await subscribeService.addSubscriberPackage(userId, packageId);
    const user_data = await userService.addPackage(userId, packageId, subscription._id);

    return res.succeed({ user_data, payment: savedPayment });
  } catch (error) {
    // 区分Razorpay API错误与内部服务错误
    if (error.error?.description) {
      return res.failed(400, "支付处理失败", error.error.description);
    }
    return res.failed(500, "Internal Server Error", error);
  }
});

关键注意事项

  • 金额单位:Razorpay API中金额以最小货币单位传入(比如100 INR需传10000,即100*100 paisa),保存到数据库时需除以100转换为正常金额格式。
  • Webhook补充:为避免前端数据篡改或丢失,建议配置Razorpay Webhook监听payment.captured事件,作为后端验证的二次保障。
  • 数据库字段设计:支付表需包含user_id、package_id、razorpay_payment_id、amount、currency、status、created_at等核心字段,便于后续对账和查询。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 16:27:23