在Node.js项目中部署越南支付网关插件

在Node.js项目中部署越南支付网关插件

要在Node.js项目中集成越南支付网关,您可以按照以下步骤操作:

1. 选择适合的越南支付网关

常见的越南支付网关包括:

  • MoMo
  • VNPay
  • ZaloPay
  • OnePay
  • Payoo

2. 安装必要的依赖包

npm install axios crypto querystring --save

3. VNPay集成示例代码

const crypto = require('crypto');
const querystring = require('querystring');
const axios = require('axios');

class VNPayment {
constructor(config) {
this.vnp_TmnCode = config.vnp_TmnCode;
this.vnp_HashSecret = config.vnp_HashSecret;
this.vnp_Url = config.vnp_Url || 'https://sandbox.vnpayment.vn/paymentv2/vpcpay.html';
this.returnUrl = config.returnUrl;
}

createPayment(orderInfo, amount, orderId, ipAddr) {
const dateFormat = require('dateformat');

let vnp_Params = {};
vnp_Params['vnp_Version'] = '2.1.0';
vnp_Params['vnp_Command'] = 'pay';
vmp_Params['vmp_TmnCode']=this.tmnCode;

// ...其他参数设置...

// Secure hash生成
const signData=querystring.stringify(vmpParams,'','&');

return `${this.url}?${signData}&vmp_SecureHash=${secureHash}`;
}
}

//使用示例:
const payment=newVNPayment({
tmncode:"YOURTMNCODE",
secretKey:"YOURSECRETKEY",
url:"https://sandbox...",//测试环境URL
returnurl:"http://yourdomain.com/return"
});

router.post('/create-payment',(req,res)=>{
const{amount}=req.body;

const paymentUrl=payment.createPayment(
"Thanh toan don hang",//订单描述
amount*100,//金额(VND)
Date.now(),//订单ID
req.ip //客户IP地址
);

res.json({payment_url:paymentUrl});
});

4.MoMo集成示例代码

class MomoPayment{
constructor(config){
this.partnerCode=config.partnerCode||'MOMO';
this.accessKey=config.accessKey;
this.secretkey=config.secretkey;
}

async createRequest(amount){
try{
let rawSignature=`partnerCode=${this.partnerCode}&accessKey=${this.accessKey}
&requestId=${Date.now()}&amount=${amount}
&orderId=MOMO${Date.now()}`;

//创建签名...

return await axios.post("https://test-payment.momo...",requestBody);
}catch(err){
console.error(err);
throw err;
}
}
}

5.ZaloPay集成示例

class ZaloPayService{
constructor(appid,key1){/*...*/}

async createOrder(params){
/*Zalo特有逻辑*/
}
}

最佳实践建议:

1.环境配置:
-为开发/生产环境使用不同配置

2.错误处理:

try{/*调用API*/}catch(e){logError(e)}

3.日志记录:记录所有交易请求和响应

4.安全考虑:
-不要在前端暴露密钥等敏感信息

5.Webhook处理:实现回调验证逻辑

需要针对特定支付网关的更详细实现或有任何问题请随时询问!

继续深入Node.js集成越南支付网关

下面我将更详细地介绍如何完善支付网关集成,包括回调处理、安全验证和最佳实践。

6. 完善VNPay回调处理

// vnpay.service.js
class VNPayment {
// ...之前的代码...

verifyReturn(query) {
const vnp_Params = {...query};
const secureHash = vnp_Params['vnp_SecureHash'];

delete vnp_Params['vnp_SecureHash'];
delete vnp_Params['vnp_SecureHashType'];

// 按字母顺序排序参数
const sortedParams = this.sortObject(vmp_Params);

// 生成校验签名
const signData = querystring.stringify(sortedParams, '', '&');
const hmac = crypto.createHmac('sha512', this.vmp_HashSecret);
const signed = hmac.update(Buffer.from(signData, 'utf-8')).digest('hex');

return secureHash === signed;
}

sortObject(obj) {
return Object.keys(obj).sort().reduce((result, key) => {
result[key] = obj[key];
return result;
}, {});
}
}

// callback.controller.js
router.get('/vnpay-return', (req, res) => {
try{
if(!payment.verifyReturn(req.query)){
return res.status(400).send('Invalid signature');
}

// TODO:更新订单状态逻辑...

if(req.query.vmp_ResponseCode === '00'){
res.send('Payment success!');
}else{
res.send(`Payment failed: ${req.query.vmp_ResponseMessage}`);
}
}catch(e){
console.error(e);
res.status(500).send('Server error');
}
});

7.MoMoWebhook处理示例

// momo.webhook.js 
router.post('/momo-callback',express.json(),async(req,res)=>{
try{
/*1.验证签名*/

/*2.检查交易状态*/

/*3.更新数据库*/

}catch(err){/*错误处理*/}
});

function verifySignature(rawSignature,signature){
/*使用secretKey验证HMAC SHA256签名*/
}

8.ZaloPayIPN处理器

constzalopayIPN=async(orderId)=>{

/*1.调用ZaloAPI查询订单状态*/

/*2.与本地记录比对*/

/*3.resolve/rejectpromise*/

}

高级配置建议:

9.RateLimiting:防止暴力攻击

app.use('/payment-api',rateLimit({
windowMs:15*60*1000,
max:100//每个IP限制请求数
}));

10.DatabaseIntegration:存储交易记录模型示例(Mongoose)

const paymentSchema=new mongoose.Schema({
gateway:{type:String},//"VNPAY/MOMO"
amount:{type:Number},
status:{type:String},//pending/success/failed
transactionId:{type:String},
createdAt:{type:Date}
});

const Payment=mongoose.model("Payment",paymentSchema);

async function saveTransaction(paymentData){
await Payment.create(paymentData);
}

11.TestingStrategy:模拟支付流程的测试用例

 it("should generate valid payment URL",()=>{...})
it("should detect tampered callback",()=>{...})
})

需要我针对某个特定部分如:
-某个网关的完整SDK封装?
-与前端Vue/React的交互示例? -性能优化技巧?
请告诉我您的具体需求方向。

# 深入支付网关集成的进阶实现

下面我将提供更完整的SDK封装、前端交互方案和性能优化策略,帮助您构建生产级支付解决方案。

12. 完整VNPay SDK封装示例

“`javascript
// lib/vnpay.js
const crypto = require(‘crypto’);
const querystring = require(‘querystring’);

class VNPaySDK {
constructor(config) {
this.validateConfig(config);

this.config = {
tmnCode: config.tmnCode,
secretKey: config.secretKey,
returnUrl: config.returnUrl,
apiUrl: config.apiUrl || ‘https://sandbox.vnpayment.vn’,
currency: config.currency || ‘VND’,
locale: config.locale || ‘vn’
};

this.logger = config.logger || console;
}

validateConfig(config) {
if (!config.tmnCode || !config.secretKey) {
throw new Error(‘Missing required configuration (tmnCode, secretKey)’);
}
}

async createPayment(orderData) {
const { orderId, amount, description, clientIp } = orderData;

const paymentParams = {
vnp_Version: ‘2.1.0’,
vnp_Command: ‘pay’,
vnp_TmnCode: this.config.tmnCode,
vnp_Amount: Math.round(amount * 100), // Convert to cents
vnp_CreateDate: new Date().toISOString().replace(/[-T:.Z]/g, ”),

// …其他参数…

return `${this.getPaymentUrl()}?${queryString}&vnp_SecureHash=${secureHash}`;
}

getPaymentStatus(params){
/*调用VNPay查询API*/
}
}

module.exports = VNPaySDK;
“`

13.React前端集成示例

“`jsx
// PaymentButton.jsx
import axios from’axios’;

export default function PaymentButton({amount}){

const handlePayment=async()=>{
try{
const res=await axios.post(‘/api/payments’,{
gateway:’vnpay’,
amount
});

window.location.href=res.data.payment_url;
}catch(err){/*错误处理*/}
};

return
}
“`

14.Vue3组合式API集成

“`vue


“`

高级安全措施:

15.SensitiveDataProtection

“`js
//使用环境变量加密存储密钥(vault.js)
const vault={
get(key){
return decrypt(process.env[`PAYMENT_${key}`]);
}
};

//在控制器中:
const secret=vault.get(‘VNPAY_SECRET’);
“`

16.RequestValidationMiddleware

“`js
function validateCreateRequest(req,res,next){
Joi.object({
amountJoi.number().min(1000).required(), //最小10k VND
}).validateAsync(req.body)
.then(()=>next())
.catch(next); //传递到错误处理器

app.post(‘/payments’,validateCreateRequest,(req.res)=>{});
“`

性能优化技巧:

17.CachingFrequentQueries

“`js
const NodeCache=require(“node-cache”);
const gatewayCache=new NodeCache({stdTTL600});

async function getGatewayStatus(gatewayId){

if(gatewayCache.has(gatewayId)){
return gatewayCache.get(gatewayId);
}

const status=await fetchRemoteStatus();

gatewayCache.set(gatewayIdstatus);
return status;
}
“`

需要我继续展开哪个方面的内容?例如:
-具体某个支付网关的完整业务流程?
-与AWS/GCP云服务的整合方案?
-高并发场景下的处理策略?
-PCI DSS合规性建议?

Categories: