使用Node.js集成Razorpay支付
支付网关是一种提供在线金融交易解决方案的技术,可以将其视为电子商务或任何在线业务的中间渠道,用于进行支付和接收任何目的的付款。
示例问题陈述: 这是一个简单的HTML页面,我们在页面上有一个按钮,用于支付499.00卢比的金额。最终,用户将点击该按钮,我们希望以某种方式接收该金额,然后我们可以决定如何提供课程的访问权限,但这不是本文章讨论的内容。

方法: Razorpay是一种流行的支付网关,它使我们能够访问包括信用卡、借记卡、网银、UPI和其他钱包(如airtel money、payZapp等)在内的所有支付方式。它还提供了一个仪表板,可以监控所有活动。它可以与任何在线应用程序集成,使在线企业与客户的互动变得更加容易。Razorpay帮助我们提供和处理所有必要的功能。在这里,我们将讨论如果我们的应用程序的后端是NodeJS,我们如何实现这一点。
服务器与前端之间的通信的示意流程图
这是内部所有事物如何相互交互的基本图表,如果从1到8的每个步骤都成功,则我们将成功地实现我们的目标。从步骤1到4,我们正在创建订单并接收响应,然后从步骤5到6,我们正在接收该订单的付款,最后两个步骤中,我们正在验证响应的真实性,即它是否来自Razorpay服务器。箭头根据时间进行设计。

步骤一步实施:
步骤1: 首先,在终端中输入以下命令以创建一个Node.js应用程序。
npm init
这将要求您针对您的项目进行一些配置,您可以相应地填写它们,还可以稍后从package.json文件中进行更改。然后为后端服务器创建一个 app.js 文件,并为前端创建一个 index.html 文件。
步骤2: 现在,安装所需的模块。
npm install express //To run nodejs server
npm install razorpay //To use razorpay utilities
项目结构: 它将如下所示。

步骤3: 想要访问Razorpay的API,您必须先获取密钥,因此请前往Razorpay注册并进入仪表板中的设置部分, 点击生成API密钥,然后您将获得key_id和key_secret,通过这些密钥您可以获取到Razorpay实例。

步骤4: 导入Razorpay并创建一个 新实例 的Razorpay,该实例在访问Razorpay的任何资源时都是必需的。在构造函数中提供一个包含key_id和key_secret的对象。
以下是后端和前端的基本初始代码实现。
App.js
// Inside app.js
const express = require('express');
const Razorpay = require('razorpay');
// This razorpayInstance will be used to
// access any resource from razorpay
const razorpayInstance = new Razorpay({
// Replace with your key_id
key_id: rzp_test_fiIwmRET6CApc2,
// Replace with your key_secret
key_secret: YAEUthsup8SijNs3iveeVlL1
});
const app = express();
const PORT = process.env.PORT || '5000';
// Here we will create two routes one
// /createOrder and other /verifyOrder
// Replace these comments with the code
// provided later in step 2 & 8 for routes
app.listen(PORT, ()=>{
console.log("Server is Listening on Port ", PORT);
});
index.html
<!-- Inside index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta content=
"This is a demo of Web integration
of Razorpay in NodeJS"
author="Mr. Twinkle Sharma" />
<title>Razorpay Web-Integration</title>
</head>
<body>
<hr/>
<h2>Advanced Data Structures & Algorithms Course</h2>
<h3>Description</h3>
<ul>
<li>Best Course for SDE placements</li>
<li>
Available in 4 major Languages JAVA,
C/C++, Python, Javascript
</li>
<li>Lifetime Access</li>
</ul>
<span> Cost:- 499 Rupees
<button id="pay-button" >
Pay Now & Get Access
</button>
</span>
<hr/>
<!-- Processing Payment Checkout -->
<!-- We will write code for payment here,
Replace this comment with the code we
are explaining below in step 5 of the
article -->
</body>
</html>
步骤5: 从前端向我们的NodeJS服务器发送订单信息。
在 app.js 中创建一个路由来接收用户请求的订单数据,这里我们使用express因为它更简单并且被许多开发者使用。我们在我们的NodeJS服务器app.js中设置了 ‘/createOrder’ 路由来接收来自客户端的数据,并且我们从‘ req. body’ 中发送订单数据。
为了简化事情,这里使用了Postman作为客户端,您可以根据自己的方式很容易地从前端发送post请求。
注意: 在与服务器交互之前,请确保每次成功运行服务器。

步骤6: 从我们的NodeJS服务器向Razorpay服务器发送订单信息。
我们从 req.body 提取出了订单信息在我们的服务器上,现在我们需要将它发送到Razorpay服务器进行进一步处理。之前我们创建的razorpayInstance将用于从Razorpay访问订单API,并且create是创建订单的方法,它接受两个参数,第一个是选项对象,另一个是回调函数,回调函数会根据成功或失败提供给我们响应。
App.js
//Inside app.js
app.post('/createOrder', (req, res)=>{
// STEP 1:
const {amount,currency,receipt, notes} = req.body;
// STEP 2:
razorpayInstance.orders.create({amount, currency, receipt, notes},
(err, order)=>{
//STEP 3 & 4:
if(!err)
res.json(order)
else
res.send(err);
}
)
});
步骤7: 收到来自Razorpay的订单响应并发送到我们的NodeJS服务器。
然后,Razorpay服务器处理收到的数据并从其服务器发送订单响应,这里我们合并了第3步和第4步,因为在这个小项目中将它们分开没有意义,分离在使用真实数据库和足够大的项目时可能会有用。下面是来自Razorpay服务器的成功返回响应。

说明:
我们从Razorpay服务器收到了一个JSON响应,状态码为200,这意味着一切正常,订单已成功创建。JSON的说明如下:
id :一个唯一的订单ID,在支付过程中会使用。
entity :一个缩写,表示该响应对应的任何订单。
amount :订单的总金额,以 货币的最小单位 表示。
amount_paid :订单的支付金额,用于部分支付时。
amount_due :总金额减去部分支付金额。
currency :金额的货币类型,可以在这里查看支持的货币列表。
receipt :订单的收据。
offer_id :用于享受某些优惠,当订单有折扣或特别优惠时使用。
status :订单的状态,例如:订单已创建、已尝试或已支付。
attempts :用户尝试支付的总次数。
notes :这是一个简单的附加信息对象。
created_at :订单创建的时间,采用UNIX时间格式。
下面是在Razorpay Dashboard上创建的订单和状态为”created”,这意味着订单刚刚被创建,如果后续的支付失败,状态将变为”attempted”,如果成功,状态将变为”paid”。

注意:我们正在一个API端点“/createOrder”中处理所有初始流程,但是随着项目的发展,根据需要将所有内容进行分离是很好的。
步骤8:从前端发送请求到Razorpay服务器以捕获付款。
现在,我们已经创建了一个订单,我们可以继续结账以接收金额。下面是Razorpay提供的在index.html中使用的代码片段,它自己处理所有事情,从在前端渲染模态UI到在后端处理付款结账,它需要的是一些配置、与银行/钱包相关的凭据和订单ID。
index.html
<!--Inside index.html -->
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
<script>
var options = {
"key": "rzp_test_fiIwmRET6CApc2",
"amount": "49900",
"currency": "INR",
"name": "Dummy Academy",
"description": "Pay & Checkout this Course, Upgrade your DSA Skill",
"image": "https://media.geeksforgeeks.org/wp-content/uploads/
20210806114908/dummy-200x200.png",
"order_id": "order_HdPuQW0s9hY9AU",
"handler": function (response){
console.log(response)
alert("This step of Payment Succeeded");
},
"prefill": {
//Here we are prefilling random contact
"contact":"9876543210",
//name and email id, so while checkout
"name": "Twinkle Sharma",
"email": "smtwinkle@gmail.com" .
},
"notes" : {
"description":"Best Course for SDE placements",
"language":"Available in 4 major Languages JAVA,
C/C++, Python, Javascript",
"access":"This course have Lifetime Access"
},
"theme": {
"color": "#2300a3"
}
};
var razorpayObject = new Razorpay(options);
console.log(razorpayObject);
razorpayObject.on('payment.failed', function (response){
console.log(response);
alert("This step of Payment Failed");
});
document.getElementById('pay-button').onclick = function(e){
razorpayObject.open();
e.preventDefault();
}
</script>
解释:
第一个脚本标签在加载一个来自Razorpay服务器的js文件。它里面有一些代码,负责执行整个代码片段。在第二个脚本标签中,我们创建了一个对象,稍后将发送到Razorpay服务器以进行付款处理。
这是关于选项的描述,带*的字段是必填的,其他字段是可选的,它们在Razorpay服务器上有默认值。
1. key: 您从仪表板获得的Razorpay key_id。
2. amount: 要支付的金额。
3. currency: 三个字符的货币字符串。
4. Name: 公司名称,将显示在UI模态框中。
5. order_id: 必须是由Razorpay生成的有效订单ID,我们将使用之前创建的订单ID。
6. description: 购买的简单描述,也将显示在模态框中。
7. image: Logo的链接,最小尺寸为256×256像素,最大大小为1MB,用于显示在模态框中的公司Logo,在我们的示例中,我们使用的是一个虚拟的Logo。
8. handler: 这是一个在付款成功时将被执行的函数,我们只是弹出一个警告和打印到控制台,但是可以很容易地修改以定制功能。
9. theme: 一个对象,可以用来根据您的应用程序UI设置模态框的主题,例如,您可以使用十六进制代码设置颜色和背景颜色。
10. prefill: 在UI呈现时要预填的详细信息,例如,您可以预填电子邮件和姓名,以免用户被询问。此外,如果您可以知道用户的历史,您还可以根据他的偏好预填付款方式。
11. notes: 这是一个用于附加信息的简单对象。
Razorpay还有更多在此未使用的选项,您可以根据它们自定义应用程序。现在,在所有这些之后,我们调用了Razorpay函数,该函数在第一个脚本标签所包含的文件中声明,它以对象参数形式接收,并返回一个Razorpay对象,该对象具有一些预定义的和用户定义的功能,这就是为什么Razorpay要求我们配置选项。让我们来看一下通过使用console.log来查看这些细节。

我们有很多返回的数据,比如,模态对话框在我们点击相应按钮后将在屏幕上呈现,事件’payment.failed’注册的函数意味着我们会在稍后看到如何使用它,还有id和其他必需的内容。现在回到代码解释,在获取Razorpay对象后,我们注册了一个回调函数,该函数在事件’ payment.failed ‘时执行,这是由Razorpay进行配置的。随后,我们使用了一个基本的Web API来根据id获取元素,该元素选择与该id相关联的按钮并执行函数。 razorpayObject.open(); 打开一个包含所有必要功能的模态窗口,以进行结账。
e.preventDefault(); 阻止浏览器对事件进行默认配置。
输出:

上述输出的解释如下:
- 用户点击与支付相关的按钮。
- Razorpay提供的模态框打开在窗口中央,您是否注意到在发送请求之前设置的公司名称、描述和徽标在这里呈现,联系电话和电子邮件也已预填。
- 即使我们预填了一些详细信息,但在进行付款过程中我们仍然可以更改它们。
- 然后,我们可以继续支付,假设我们选择了信用卡支付方式,在这里我们输入了一个虚拟信用卡详细信息“卡号4111 1111 1111 1111”,有效期可以是任意将来的月/年,CVV可以是任意三位数字,卡持有人的姓名也在此处预填,但您可以在继续之前进行编辑。
- 然后,Razorpay将立即处理支付。
- 付款完成后,Razorpay再次要求您是否同意支付,点击“成功”继续支付或点击“失败”拒绝。
步骤9: 从Razorpay接收付款响应到前端。
在成功完成步骤8后,我们将在前端收到Razorpay的响应,其中包括付款ID、签名、订单ID等。否则,响应将是失败的,同时还会附带一些失败的原因。下面是成功返回的响应的console.log。

步骤10: 从前端向我们的NodeJS服务器发送支付响应
我们在服务器上创建了一个名为 ‘/verifyOrder’ 的API端点来接收支付数据。在这里,我们使用Postman作为客户端发送数据,您可以以自己的方式发送数据的POST请求。
从支付响应中收到的签名已通过 自定义标头 “x-razorpay-signature”发送,将“x-”放在标头名称之前是一种惯例,而支付ID和订单ID则已从 请求体中发送。

步骤11:验证真实性并向用户发送相应的回应
尽管我们已经收到了付款,但如果没有验证,我们无法向用户发送响应。因此,这是验证步骤,正如您所知,我们收到了一些东西,如razorpay_payment_id、razorpay_order_id、razorpay_signature以及一些其他关于成功付款的信息。现在,您要如何知道这些信息对应于有效的付款,并且它必须已经在您的Razorpay仪表板中被捕获了呢?因为可能会有某些情况,某人可能以某种方式发送虚假的响应,而您将把该付款视为已捕获的。因此,为了验证,请使用服务器上使用已完成付款的order_id和从响应中返回的razorpay_payment_id创建一个签名,同时在此步骤中,您还将需要在生成API密钥时从控制面板上获得的key_secret。
现在使用 SHA256算法, 它是一个加密函数,接收一些参数并返回一个密码哈希,可以根据所给的密钥代码来验证某些内容。根据 预定义的Razorpay语法 构建一个 HMAC十六进制 摘要:
generated_signature = **HMAC-SHA256(order_id + "|" + razorpay_payment_id, secret);**
//HMAC-SHA256:- This is just a naming convention, HMAC-X means the X cryptographic
//function has been used to calculate this hash
if ( **generated_signature === razorpay_signature** ) {
//payment is successful, and response has been came from authentic source.
}
注意:- 如果您的应用程序足够大,并且不想每次都进行此验证,有一种简单的方法可以在Razorpay仪表板上设置webhook(webhook是根据实时事件将信息发送到另一个应用程序的方法),您可以探索一下。
app.js
//Inside app.js
app.post('/verifyOrder', (req, res)=>{
// STEP 7: Receive Payment Data
const {order_id, payment_id} = req.body;
const razorpay_signature = req.headers['x-razorpay-signature'];
// Pass yours key_secret here
const key_secret = YAEUthsup8SijNs3iveeVlL1;
// STEP 8: Verification & Send Response to User
// Creating hmac object
let hmac = crypto.createHmac('sha256', key_secret);
// Passing the data to be hashed
hmac.update(order_id + "|" + payment_id);
// Creating the hmac in the required format
const generated_signature = hmac.digest('hex');
if(razorpay_signature===generated_signature){
res.json({success:true, message:"Payment has been verified"})
}
else
res.json({success:false, message:"Payment verification failed"})
});
输出:
这是我们从验证订单API接收到的响应,由于我们的付款是真实的,它返回了一个成功的响应,状态码200表示一切都正常。

现在就是这样了,通过这一系列操作,我们成功创建了一个订单,收到了款项,并且验证了其真实性。
这是支付和订单的 分账簿 ,显示在仪表板上,被捕获的状态意味着我们成功收到了款项,而已支付意味着订单金额已经支付。

极客教程