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

Node.js如何集成Razorpay?附完整实现示例参考

Node.js 对接 Razorpay 支付集成实现方案

整个流程是生产验证过的标准对接逻辑,照着配置基本不会踩坑。

前置准备

  • 先在Razorpay商户后台拿到对应环境的Key ID和Key Secret,测试阶段用测试密钥,上线前切换生产密钥即可
  • 本地Node.js版本尽量用12.x及以上,避免SDK版本兼容问题
  • 密钥不要硬写在业务代码里,统一存在环境变量中,避免泄露导致账户被盗刷

1. 安装官方SDK

直接安装官方维护的SDK包即可,不用找第三方封装版本:

npm install razorpay
# 用yarn的话执行这个命令
yarn add razorpay

2. 初始化SDK实例

初始化操作必须在服务端完成,Key Secret绝对不能泄露到前端代码中:

const Razorpay = require('razorpay');

const rzpInstance = new Razorpay({
  key_id: process.env.RAZORPAY_KEY_ID,
  key_secret: process.env.RAZORPAY_KEY_SECRET
});

3. 服务端创建支付订单

订单必须由服务端生成,不要在前端计算金额直接传,很容易被恶意篡改。注意Razorpay所有金额接口都按最小货币单位传值,印度卢比场景下1卢比=100派沙,比如要收100卢比就得传10000,别直接传100,很多新手第一次对接都会踩这个坑。
以Express框架为例写个订单创建接口:

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

app.post('/api/pay/create-order', async (req, res) => {
  try {
    const { amount, currency = 'INR', bizOrderId } = req.body;
    const order = await rzpInstance.orders.create({
      amount: amount * 100, // 转换为最小货币单位
      currency,
      receipt: bizOrderId || `rcpt_${Date.now()}`,
    });
    res.json({
      code: 0,
      data: {
        rzpOrderId: order.id,
        amount: order.amount,
        currency: order.currency,
        payKey: process.env.RAZORPAY_KEY_ID
      }
    })
  } catch (err) {
    res.status(500).json({code: -1, msg: '订单创建失败', err: err.message})
  }
})

4. 前端拉起支付弹窗

前端先请求自己的服务端拿到订单参数,再引入Razorpay前端Checkout脚本拉起支付弹窗即可。注意支付完成后前端拿到的回调参数不能直接作为支付成功依据,必须传回后端做验签:

<!-- 引入前端支付弹窗脚本 -->
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
<script>
async function startPay(amount) {
  // 先请求自有后端拿订单参数
  const orderRes = await fetch('/api/pay/create-order', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({amount})
  }).then(res => res.json());
  if(orderRes.code !== 0) return alert('订单初始化失败');

  const payOptions = {
    key: orderRes.data.payKey,
    amount: orderRes.data.amount,
    currency: orderRes.data.currency,
    name: "你的商户/店铺名称",
    description: "商品购买支付",
    order_id: orderRes.data.rzpOrderId,
    handler: function(resp) {
      // 将回调参数全量传回后端做验签
      verifyPayResult(resp);
    },
    prefill: {
      name: "用户昵称",
      email: "user@demo.com",
      contact: "用户手机号"
    },
    theme: { color: "#2563eb" }
  }
  const payInstance = new Razorpay(payOptions);
  payInstance.open();
}

async function verifyPayResult(payResp) {
  const verifyRes = await fetch('/api/pay/verify', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify(payResp)
  }).then(res => res.json());
  alert(verifyRes.code === 0 ? '支付成功' : '支付验证失败');
}
</script>
<button onclick="startPay(100)">支付100卢比</button>

5. 服务端验签确认支付有效性

这步是必做项,不能省略,否则攻击者可以伪造支付成功请求绕过校验。Razorpay会用密钥给支付结果生成签名,服务端按照相同规则计算签名做对比,签名一致才代表支付真实有效:

const crypto = require('crypto');

app.post('/api/pay/verify', (req, res) => {
  try {
    const { razorpay_order_id, razorpay_payment_id, razorpay_signature } = req.body;
    const signPayload = `${razorpay_order_id}|${razorpay_payment_id}`;
    const expectedSign = crypto.createHmac('sha256', process.env.RAZORPAY_KEY_SECRET)
      .update(signPayload)
      .digest('hex');
    
    if(expectedSign === razorpay_signature) {
      // 签名校验通过,在这里更新自有数据库的订单状态为已支付,走后续发货/开通权益逻辑
      res.json({code: 0, msg: '支付成功'});
    } else {
      res.status(400).json({code: -1, msg: '签名非法,支付无效'});
    }
  } catch (err) {
    res.status(500).json({code: -1, msg: '验签出错', err: err.message})
  }
})

常见踩坑提醒

  • 所有涉及Key Secret的操作必须放在服务端,一旦泄露到前端代码,他人拿到后可以直接操作你的Razorpay账户
  • 除了前端支付完成的回调,建议配置Razorpay的Webhook异步接收支付状态通知,避免用户付完钱直接关闭页面导致前端回调没触发,出现丢单
  • 测试阶段直接用Razorpay官方提供的测试卡信息做流程验证,不要绑定真实银行卡,也不要提前切换生产密钥
  • 退款、订单查询、账单导出等扩展功能,直接调用初始化好的rzpInstance实例上的对应方法即可,参数传对基本不会出问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 08:06:21