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
相关产品推荐
相关产品推荐

