近期我各种百度搜索wx支付功能,不过好多文章都有各种Bug,再加上微信小程序的微信支付真的恶心至极~~~~然后机制的我东拼西凑的功夫不负有心人我终于把微信支付功能拼接起来了。
首先nodejs需要的库。
xml2js、request、axios、crypto
怎么安装相信大家都懂了,废话不多说上才艺~
首先需要获取微信openID。
/** 小程序代码 */
wx.login({
success:function(res){
// 发送后端校验
wx.request({
url: url+'/all/wx',
data:{
code: res.code,
},
success(res){
var openid = res.data.openid
// 保存storage
wx.setStorageSync('openid', openid)
}
})
}
})
/** node代码 */
/**获取wxOpenID */
router.get('/wx', async(req, res)=>{
var query = req.query
let {data} = await axios.get('https://api.weixin.qq.com/sns/jscode2session?',{
params:{
appid: 小程序 appId,// 小程序 appId
secret: 小程序 appSecret,// 小程序 appSecret
js_code:`${query.code}`,// 登录时获取的 code
grant_type:'authorization_code',// 授权类型,此处只需填写 authorization_code
}
})
res.send(data)
})
获取到openID发到后端
/** 小程序代码 */
wx.request({
url: url+'/all/wxPay',
data:{
money:1,// 支付金额
openid: wx.getStorageSync('openid'),// openID
title:title,// 标题
id:id,// 支付ID这里我做了一个随机ID
},
success:res =>{
let data = res.data.result
if (res.data.error_code == 0) {
var _signtext = "appId=" + APPID + "&nonceStr=" + res.data.result.nonceStr + "&package=prepay_id=" + res.data.result.package + "&signType=MD5&timeStamp=" + res.data.result.timeStamp + "&key=" + MchKey;
// Md5签名,所谓签名就是再次加密一下然后再进行调取
var sign = hexMD5(_signtext)
//成功调用requestPayment
// 注意星号一定要注意注意
wx.requestPayment({
timeStamp: data.timeStamp + '',//*** 一定要在后面 + '',否则没办法调取
nonceStr: data.nonceStr,
package: "prepay_id=" + data.package,//*** 一定要在前面加prepay_id=,否则也是没办法调取
signType: 'MD5', //签名算法
paySign: sign.toUpperCase(),// 二次签名
success:e =>{
console.log(e)
},
fail:err =>{
console.log(err)
}
})
} else {
console.log(res, "支付失败!"+res.msg);
}
}
})
/** node代码 */
router.get('/wxPay',async (req, res)=>{
var {money,openid,id,title} = req.query
var nonceStr = util.randomStr()// 随机字符串
//签名
var signoption = {
appid: config.wxConfig.APPID,//小程序appid
body: title,//商品描述
mch_id: config.wxConfig.mchID,//商户号
nonce_str: nonceStr,//随机字符串
notify_url: 'http://XXXXXX/', //回调地址
openid: openid,//交易类型是JSAPI的话,此参数必传 可从过code获取openid
out_trade_no: id,//商品订单号
spbill_create_ip: '000.000.0.0',//因为微信支付需要有回调url,所以没法确定你的公网ip就没法发送订单支付通知给你,所以提供一个解析的正常ip就好
total_fee: money,//商品价格
trade_type: 'JSAPI'//交易类型,JSAPI为小程序交易类型
};
var sign = util.createSign(signoption)
let reqUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
// xml格式
//这个顺序要和签名顺序一致
let formData = `<xml>
<appid>${signoption.appid}</appid>
<body>${title}</body>
<mch_id>${config.wxConfig.mchID}</mch_id>
<nonce_str>${nonceStr}</nonce_str>
<notify_url>http://localhost:XXXXX/</notify_url>
<openid>${openid}</openid>
<out_trade_no>${id}</out_trade_no>
<spbill_create_ip>000.000.0.0</spbill_create_ip>
<total_fee>${money}</total_fee>
<trade_type>JSAPI</trade_type>
<sign>${sign}</sign>
</xml>
`
// 发送请求
request({
url: reqUrl,
method: "POST",
json: true,
headers: {
"content-type": "application/json"
},
body: formData
},function(error, response, body){
if (!error && response.statusCode === 200) {
try {
xml2js.parseString(body, function (error, result) {
let reData = result.xml;
let responseData = {
timeStamp: new Date().getTime(),// 时间戳
nonceStr: reData.nonce_str[0],// 随机字符串
package: reData.prepay_id[0],// 微信返回链接
paySign: reData.sign[0],// 签名
};
// 返回客户端
res.json({ error_code: 0, result: responseData });
});
} catch (e) {
console.log(e);
}
}
})
node这里面所需要注意就是签名和xml,还有随机字符串
//签名【一定严格要求顺序】
var signoption = {
appid: config.wxConfig.APPID,//小程序appid
body: title,//商品描述
mch_id: config.wxConfig.mchID,//商户号
nonce_str: nonceStr,//随机字符串
notify_url: 'http://XXXXXX/', //回调地址
openid: openid,//交易类型是JSAPI的话,此参数必传 可从过code获取openid
out_trade_no: id,//商品订单号
spbill_create_ip: '000.000.0.0',//因为微信支付需要有回调url,所以没法确定你的公网ip就没法发送订单支付通知给你,所以提供一个解析的正常ip就好
total_fee: money,//商品价格
trade_type: 'JSAPI'//交易类型,JSAPI为小程序交易类型
};
// 调取createSign进行签名
var sign = util.createSign(signoption)
//签名算法(把所有的非空的参数,按字典顺序组合起来+key,然后md5加密,再把加密结果都转成大写的即可
createSign(obj){
var stringA = 'appid=' + obj.appid + '&body=' + obj.body + '&mch_id=' + obj.mch_id + '&nonce_str=' + obj.nonce_str + '¬ify_url=' + obj.notify_url + '&openid=' + obj.openid + '&out_trade_no=' + obj.out_trade_no + '&spbill_create_ip=' + obj.spbill_create_ip + '&total_fee=' + obj.total_fee + '&trade_type=' + obj.trade_type;
var stringSignTemp = stringA + '&key=' + config.wxConfig.SHOP_KEY;
var hash = crypto.createHash('md5');
stringSignTemp = hash.update(stringSignTemp);
var signValue = hash.digest('hex');
return signValue.toUpperCase();
},
xml格式
//这个顺序要和签名顺序一致
let formData = `<xml>
<appid>${signoption.appid}</appid>
<body>${title}</body>
<mch_id>${config.wxConfig.mchID}</mch_id>
<nonce_str>${nonceStr}</nonce_str>
<notify_url>http://localhost:8080/</notify_url>
<openid>${openid}</openid>
<out_trade_no>${id}</out_trade_no>
<spbill_create_ip>000.000.0.0</spbill_create_ip>
<total_fee>${money}</total_fee>
<trade_type>JSAPI</trade_type>
<sign>${sign}</sign>
</xml>
`
随机字符串
//产生一个随机字符串【32位】
randomStr(){
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<=32;i++){
var random = Math.floor(Math.random()*arr.length);
str += arr[random];
}
return str;
},
还有还有最重要的就是记得微信支付要用APIV2密钥啊,一定一定32位字符串,不然会失败的我就是倒霉鬼,用了V3密钥在官网测试就提示成功,结果在小程序一致签名错误,结果换V2的成功了