微信v2支付
799字约3分钟
2024-07-16
Node服务端接入微信支付v2写法
在接入之前需要安装axios、xml2js,用于发送网络请求,以及将自己的订单信息转换为微信支付所需要的xml字符串类型。
npm install axios
npm install xml2js
建议和提醒
建议参考面向对象写法,方便后期维护和扩展。我这边把基础功能写成一个方法分开方面理解和写。(当前是使用的:native支付.)
功能模块引入
// 解析和生成xml
import xml2js from 'xml2js'
// 调用支付网络请求
import axios from 'axios'
// 加密模块
import crypto from 'crypto'
订单号生成
/**
* 生成订单号
* @param length 长度,默认32
* @returns 订单号
*/
function randomNumber(length:number = 32):string{
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let noceStr = '';
let maxPos = chars.length;
while (length--) noceStr += chars[Math.random() * maxPos | 0];
return noceStr;
}
加密签名v2
/**
* 生成加密签名
* @param info 订单对象
* @param key 微信支付key密钥
* @returns 签名信息
*/
function createSignV2(info:object, key:string):string {
const hash = crypto.createHash("md5");
let stringA = "";
let keys = Object.keys(info);
keys.sort();
for (let item of keys) {
stringA += `${item}=${info[item]}&`;
}
let stringSignTemp = `${stringA}key=${key}`;
return hash.update(stringSignTemp).digest("hex");
}
微信购买下单
/**
* 购买下单
* @param {*} money 购买金额
* @returns 下单结果
*/
async function wxpay(money) {
let orderInfo = {
// 商户号ID
mch_id: "162xxxxxxx",
// 公共账号ID
appid: "wx0xxxxxxxxxxx",
// 商品描述
body: "我是在购买名叫xx的商品",
// 支付通知地址最好是在线能访问的 post 接口 在线能访问的
notify_url: "https://www.osdaklshad.cn",
// 支付类型
trade_type: "NATIVE",
// 随机字符串 支付必传
nonce_str: randomNumber(),
// 订单号
out_trade_no: randomNumber(),
// 金额 以分为单位
total_fee: Number(money) * 100
};
// 签名密钥
orderInfo.sign = createSignV2(orderInfo, "2962bxxxxxxxxxxxxxxxxxxxxxxxxa4f")
let builder = new xml2js.Builder();
let xmlData = builder.buildObject(orderInfo);
try {
const wx_pay = await axios
.post("https://api.mch.weixin.qq.com/pay/unifiedorder", {
xmlData,
headers: { "Content-Type": "application/xml" },
});
var parser = new xml2js.Parser({ explicitArray: false });
const wx_result = await parser.parseStringPromise(wx_pay.data);
wx_result.xml.out_trade_no = orderInfo.out_trade_no;
wx_result.xml.total_fee = orderInfo.total_fee;
return wx_result.xml;
} catch (err) {
console.log('支付报错:', err)
}
}
微信取消订单
/**
* 取消订单
* @param {*} goods 订单号
* @returns
*/
async function closeGood(goods:string) {
let closeInfo = {
// 商户号ID
mch_id: "162xxxxxxx",
// 公共账号ID
appid: "wx08ae8bxxxxxxxxx",
out_trade_no: goods,
nonce_str: randomNumber(),
}
closeInfo.sign = createSignV2(closeInfo, "2962b0e189xxxxxxxxxxxxxxxxx")
let builder = new xml2js.Builder();
let xmlData = builder.buildObject(closeInfo);
try {
const wx_close = await axios
.post("https://api.mch.weixin.qq.com/pay/closeorder", {
xmlData,
headers: { "Content-Type": "application/xml" },
});
var parser = new xml2js.Parser({ explicitArray: false });
const wx_result = await parser.parseStringPromise(wx_close.data);
console.log('取消:', wx_result.xml)
return wx_result.xml;
} catch (err) {
console.log('取消报错:', err)
}
}
微信查看订单状态
/**
* 订单状态查询
* @param {*} goods 订单号
* @returns
*/
async function queryGood(goods) {
let queryInfo = {
// 商户号ID
mch_id: "162xxxxxxxx2",
// 公共账号ID
appid: "wx08axxxxxxx",
out_trade_no: goods,
nonce_str: randomNumber(),
}
queryInfo.sign = createSignV2(queryInfo, "2962b0e1xxxxxxxxxxxxxxxxx")
let builder = new xml2js.Builder();
let xmlData = builder.buildObject(queryInfo);
try {
const wx_query = await axios
.post("https://api.mch.weixin.qq.com/pay/orderquery", {
xmlData,
headers: { "Content-Type": "application/xml" },
});
var parser = new xml2js.Parser({ explicitArray: false });
const wx_result = await parser.parseStringPromise(wx_query.data);
console.log('查询值:', wx_result.xml)
return wx_result.xml;
} catch (err) {
console.log('查询报错:', err)
}
}
总结
你会发现,在这个所有的过程当中会有很多重复代码,列如:axios请求、订单公共信息、xm2js生成签名和解析签名等等。
建议使用面向对象写法,将公共部分提取出来,没必要让代码如此臃肿,后期还不好维护。
列如修改查询地址、商户信息都会修改多处,以上代码仅作展示,不建议用到实际项目,如果需要,还要修改。