环境
微信认证服务号,已开通微信支付
支付域名:wxpay.cyrilxu.cn
语言:nodejs
支付流程
配置
- 网页授权,为了获取openid。详见上一篇
- 配置商户,在公众号的微信支付页面,关联微信商户号
- 在微信支付商户设置,产品中心 —> 开发配置 —>支付配置—>JSAPI授权目录。现在支持根目录了
- 在微信商户设置中,账户中心—>API安全—>API密钥,设置API密钥,记住。牢记,以后只能修改不能查看。存放在服务器端
具体流程
- 获取openid,详见上一篇
- 生成订单
- 调用统一下单API获取预付单信息(prepay_id)
- 生成jsapi付款参数并签名
- 付款页付款,成功则跳转成功页
- 后台接收付款信息
- 前台请求付款信息
Talk is cheap, show you the code
获取openid,微信获取用户信息
生成订单信息:
1
2
3
4
5
6{
openid:openid,
order_num: 自己系统的订单号,
pay_money: 付款金额,单位为分,
attach: 产品名称
}
获取prepay_id:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41/**
* 获取微信统一下单的接口数据
*/
getPrepayId: async function(obj, config){
// var that = this;
// 生成统一下单接口参数
var UnifiedorderParams = {
appid : config.wxappid,
attach : obj.attach,
body : obj.body,
mch_id : config.mch_id,
nonce_str: obj.nonce_str,
notify_url : obj.notify_url,// 微信付款后的回调地址
openid : obj.openid,
out_trade_no : obj.order_num, //订单号
// spbill_create_ip : obj.spbill_create_ip,
total_fee : obj.total_fee,
trade_type : 'JSAPI',
// sign : getSign(),
};
UnifiedorderParams.sign = this.getSign(UnifiedorderParams); //签名算法,见附录
var postBody = this.getUnifiedorderXmlParams(UnifiedorderParams); //生成xml
var url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
const opt = {
url: url,
body: postBody,
method: 'POST',
// json: true,
resolveWithFullResponse: true,
}
const {statusCode, body} = await request(opt);
if (statusCode === 200) {
var prepay_id = this.getXMLNodeValue('prepay_id', body.toString("utf-8"));
var tmp = prepay_id.split('[');
var tmp1 = tmp[2].split(']');
prepay_id = tmp1[0];
return prepay_id;
}
return null;
},
生成jsapi参数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20/**
* 微信支付的所有参数
* @param req 请求的资源, 获取必要的数据
* @returns {appId: string, timeStamp: Number, nonceStr: *, package: string, signType: string, paySign: *}
*/
getBrandWCPayParams: async function(obj, config){
obj.nonce_str = this.createNonceStr(); //随机字符串
//统一下单id
const prepay_id = await this.getPrepayId(obj);
var wcPayParams = {
"appId" : config.wxappid, //公众号名称,由商户传入
"timeStamp" : parseInt(new Date().getTime() / 1000).toString(), //时间戳,自1970年以来的秒数
"nonceStr" : obj.nonce_str, //随机串
// 通过统一下单接口获取
"package" : "prepay_id="+prepay_id,
"signType" : "MD5" //微信签名方式:
};
wcPayParams.paySign = this.getSign(wcPayParams); //微信支付签名
return wcPayParams;
},
付款页js:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74var wxJsApiParam;//微信下单参数
var errMsg = '';//微信返回支付错误信息
var wexin_state = 1;//微信按钮初始状态为1,点击可下单付款,2时点击不能下单仅付款,3时不能点击
$('#paylink').on('click', function () {
console.log('wexin_state', wexin_state);
if (wexin_state == 1){
wexin_state = 3;
goWepay();
} else if (wexin_state == 2) {
callpay();
} else {
return;
}
});
//下单
function goWepay() {
$.ajax({
url: 'dopay',//获取微信支付jsapi参数:wcPayParams
type: 'POST',
dataType: 'json',
data:{
openid:openid,
order_num: order_num,
attach:attach,
pay_money:pay_money
},
success:function(data){
console.log('data:', data);
wexin_state = data.state;
wxJsApiParam = data.param;
callpay();
}
});
}
//调用微信JS api 支付
function callpay() {
console.log('WeixinJSBridge:', WeixinJSBridge);
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', jsApiCall,false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', jsApiCall);
document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
}
} else {
onBridgeReady();
}
}
function onBridgeReady(){
console.log('wxJsApiParam:',wxJsApiParam);
if (wxJsApiParam != null) {//如果订单生成成功 %>
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
wxJsApiParam,//json串
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok" ) {
console.log("ok");
window.location.href = "success?order=" + order_num;
}
// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回
// ok,但并不保证它绝对可靠。
else {
console.log("fail");
console.log(res);
// window.location.href = "/weixinpay/failed"
// alert("支付失败")
}
WeixinJSBridge.log(res.err_msg);
}
);
}
}
接收付款信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25router.post('/notify', async function (req, res, next) {
// console.log('notify post:', body);
req.on("data",async function (data) {
xmlParser.parseString(data.toString(), async function(err, result) {
var body = result.xml;
var keys = Object.keys(body);
var parseBody = {};
keys.forEach(function (key) {
if (key!='sign') {
parseBody[key] = body[key][0];
}
});
// console.log(parseBody);
if (parseBody.result_code == 'SUCCESS' && wx.getSign(parseBody) == body.sign[0]){
//业务代码
//发送成功接收
var xml = {xml:{
return_code:'SUCCESS',
return_msg:'OK'
}};
res.send(xmlBuilder.buildObject(xml))
}
});
})
});
ajax查询付款信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17function checkCode() {
$.ajax({
url: 'checkOrder?order=<%=order_num%>',
method: 'GET',
success: (data)=>{
if (data.state == 200) {
$('#check').html(data.data);
} else {
setTimeout(checkCode, 3000);
}
},
error: ()=>{
setTimeout(checkCode, 3000);
}
})
}
$(()=>{checkCode()})
附录
1 | /** |