nodejs实现微信提现到零钱
到头来自己摸索到了答案,亲测有效(已经上线),废话不多说,开始正文:
首先附上附上微信企业付款到零钱的官方文档地址微信企业付款到零钱(提现到零钱)
ready go!
- 用户付款到商户平台的账户 与 商户付款到个人的账户是相互独立的 意思是商户要付款到个人必须用自己充值到商户平台账户的钱(这个切记)。
- 一定要先开通企业付款到个人功能,之后才可以使用。
- **证书文件:**需要到商户平台下载支付证书,在引用时直接把文件存放在服务器上的绝对路径写到函数里(相对于服务器的绝对路径) 切记!切记!切记!
- 支付金额最小为100 (单位:分)。
- 字段规则要完全参照官方的事例 ,注意 ASCII的顺序(这里很重要的);
- 商户平台上一定要添加服务器地址的白名单(超级重要);
以上文字描述一定要注意!很重要!很重要!很重要!
话不多少,上代码!
const router = require('koa-router')()
const request = require('request-promise')
const md5 = require('md5-node') //引入md5加密模块
const xml2js = require('xml2js') //引入xml解析模块
const fs = require('fs')
const Utils = require('../common/utils') //方法库(这个方法库在后面会提供)
const appId = 'xxxxxxxxxxxxxxxx' //小程序的appid
const mchId = 'xxxxxxxxxxxxx' //商户号
const mchKey = 'xxxxxxxxxxxxxxxxxxxxxxx' //商户秘钥
router.post('/promotion', async function (ctx) { //小程序提现
var responseData = {};//请求返回结果
let openId = 'xxxxxxx';
let orderId = Utils.getRandomStr(8) + ctx.request.body.orderId; //商户订单号
let openId = openId; //提现用户openid
let money = ctx.request.body.money
let desc = ctx.request.body.desc;
let nonceStr = Utils.getRandomStr(32);//生成随机字符串
let amount = Number(money) * 100;//提现的金额(单位:分)
let signObj = {
mch_appid: appId,//小程序appid
mchid: mchId,//商户号
nonce_str: nonceStr,//随机字符串
partner_trade_no: orderId,//商品订单号
openid: openId,
check_name: "NO_CHECK",//是否校验提现人姓名
// re_user_name:'老王',//提现人姓名
amount: amount,//提现金额
desc: desc,//商品描述
spbill_create_ip: 'xxx.xx.xxx.xx'//本地服务器地址
};
signObj.sign = getSignParam(signObj);//将参数拼接,并进行MD5加密,生成sign值
let formData = getXmlParam(signObj);
let payResult = await WeApiPromotion(formData);
xml2js.parseString(payResult, function (error, result) {
let reData = result.xml;
if(reData.return_code[0] === 'SUCCESS'){
responseData = {
data:reData
}
}else{
responseData = {
wxReturnMsg:'微信提现API失败',
wxReturnCode:'FAIL'
}
}
})
try {
ctx.response.body = {
//成功处理
}
} catch (err) {
ctx.response.body = {
//失败处理
}
}
})
//进行签名的参数
function getSignParam(obj) {
var keys = Object.keys(obj);
keys = keys.sort();
var _str = '';
var _arr = [];
keys.forEach(function (key) {
_arr.push(key + '=' + obj[key]);
});
var _str = _str + _arr.join('&') + '&key=你的商户号';
_str = md5(_str);
var signValue = _str.toUpperCase();
return signValue;
}
//请求时的xml参数
function getXmlParam(obj) {
var _xml = '<xml>';
for (var key in obj) {
_xml += '<' + key + '>' + obj[key] + '</' + key + '>';
}
_xml = _xml + '</xml>'
return _xml;
}
//微信提现http请求
async function WeApiPromotion(formData) {
options = {
url: 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers',//微信官方请求接口
method: "POST",
headers: {
"content-type": "application/json;charset=utf-8"
},
body: formData,
agentOptions: {
key: fs.readFileSync('./common/file/wxpay/apiclient_key.pem'), //将微信生成的证书放入 cert目录下
cert: fs.readFileSync('./common/file/wxpay/apiclient_cert.pem'),
passphrase: mchId
}
};
let payData = await request(options);
return payData;
}
/****************************** Util.js ******************************/
//产生一个随机字符串,strLength值为多少,就生成长度为多少的字符串
function getRandomStr(strLength) {
var str = "";
var arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
for (var i = 1; i <= strLength; i++) {
var random = Math.floor(Math.random() * arr.length);
str += arr[random];
}
return str;
}
module.exports= {
getRandomStr
}
一定要留意本文开头的文字部分,那几条都是实实在在的“天坑”,过程中也有很多其他的小问题,但都一一解决了,这里就不详细列出,祝大家编码愉快!
打完,收工!