微信v2支付
796字约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生成签名和解析签名等等。
建议使用面向对象写法,将公共部分提取出来,没必要让代码如此臃肿,后期还不好维护。
列如修改查询地址、商户信息都会修改多处,以上代码仅作展示,不建议用到实际项目,如果需要,还要修改。