1. 新建v3PayApi.js
const fs = require("fs")
const request = require('request')
const rsa = require("./rsa")
/* 微信支付 V3接口请求 */
module.exports = class V3PayApi {
/* 接口地址 */
host = "https://api.mch.weixin.qq.com"
/* 证书私钥 pem文件 */
privateKey = fs.readFileSync(`${__dirname}/cert/apiclient_key.pem`, "utf-8")
/* 商户号 */
mchid = ""
/* 证书序列号 */
serial_no = ""
/* 请求
@param api 接口短地址
@param data 接口参数
@param query 地址携带的参数,如:?key=value
*/
http(api, data, query) {
return new Promise((r, j) => {
const requestParams = this.makeReqParams(api, data, query)
request(requestParams, function (error, resp, body) {
if(error)return j(error)
return r(body)
})
})
}
/* 组装参数 */
makeReqParams(api, _body = "", query = "") {
const body = JSON.stringify(_body)
let method = "POST"
let url = api + query
let timeStamp = parseInt(Date.now() / 1000)
let nocStr = this.getNonceStr()
let signStr = method + "\n" + url + "\n" + timeStamp + "\n" + nocStr + "\n" + body + "\n"
let sign_base64 = rsa.SignUtil.rsaSign(signStr, this.privateKey)
let authorStr = 'mchid="' + this.mchid + '",nonce_str="' + nocStr + '",signature="' + sign_base64 + '",timestamp="' + timeStamp + '",serial_no="' + this.serial_no + '"'
let params = {
url: this.host + url,
method: method,
headers: {
"Content-type": "application/json",
'Accept': 'application/json',
"User-Agent": "TitanPan/5.0",
"Authorization": "WECHATPAY2-SHA256-RSA2048 " + authorStr
},
}
if (method == "POST") {
params["json"] = true
params["body"] = _body
}
return params
}
/* 随机字符串 */
getNonceStr(len) {
len = len || 32;
var $chars =
"ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678"; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
var maxPos = $chars.length;
var pwd = "";
for (let i = 0; i < len; i++) {
pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
}
return pwd;
}
}
2. 新建rsa.js
const {KJUR, hextob64} = require('jsrsasign')
const HashMap = {
SHA256withRSA: 'SHA256withRSA',
SHA1withRSA: 'SHA1withRSA'
}
const PEM_BEGIN = '-----BEGIN PRIVATE KEY-----\n'
const PEM_END = '\n-----END PRIVATE KEY-----'
/**
* rsa签名参考:https://www.jianshu.com/p/145eab95322c
*/
exports.SignUtil = {
/**
* rsa签名
* @param content 签名内容
* @param privateKey 私钥,PKCS#1
* @param hash hash算法,SHA256withRSA,SHA1withRSA
* @returns 返回签名字符串,base64
*/
rsaSign: function (content, privateKey, hash = "SHA256withRSA") {
privateKey = this._formatKey(privateKey)
// 创建 Signature 对象
const signature = new KJUR.crypto.Signature({
alg: hash,
//!这里指定 私钥 pem!
prvkeypem: privateKey
})
signature.updateString(content)
const signData = signature.sign()
// 将内容转成base64
return hextob64(signData)
},
_formatKey: function (key) {
if (!key.startsWith(PEM_BEGIN)) {
key = PEM_BEGIN + key
}
if (!key.endsWith(PEM_END)) {
key = key + PEM_END
}
return key
}
}
3. 使用示例
当前示例用的是发起商家转账API,具体参数参考微信支付官方文档:https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter4_3_1.shtml
const V3PayApi = require("./v3PayApi.js")
let data = {
"appid": 'appid',
"out_batch_no": '20220930231828852',
"batch_name": '1664551108852测试提现单',
"batch_remark": '1664551108852测试提现单',
"total_amount": 1 * 100,
"total_num": 1,
"transfer_detail_list": [
{
"out_detail_no": '20220930231828852',
"transfer_amount": 1 * 100,
"transfer_remark": '测试用户提现',
"openid": 'openid'
}
]
}
new V3PayApi().http("/v3/transfer/batches",data).then(r=>{
console.log("suc",r)
}).catch(e=>{
console.log("err",e)
})