微信支付所经历的流程:
- 1.用户下单后,进行微信授权,获取临时凭证code值。
- 2.把code凭证发送到服务端获取openid。
- 3.通过openid、订单号,从后台获取微信支付参数。
- 4.传入支付参数,唤起微信支付。
- 5.成功、失败、取消回调处理。
第一步:微信授权,获取code值
- 点击 “立即支付” 进行微信授权操作:
- 使用GET请求方式,请求后端提供的微信授权接口,并拼接回调url参数(这里的url记得使用encodeURIComponent转码,不然会有问题);
- 请求微信授权接口后,后端会把页面重定向到支付页面,并在路径中携带我们需要的code值;
getAuthCode() {
window.location.href =
'项目域名' + '/api/v1/common/wx/auth?callbackUrl=' +
encodeURIComponent('项目域名' + '/order-pay/') // 唤起微信授权
}
- 获取支付页面url路径中的code值:
- 如果有code值,则直接返回code值,若没有code值,则返回false;
- 拿到code值,接着去获取openid;
getQueryVariable() {
// 获取url中的指定参数值
const text_html = window.location.href // 获取当前路径
let trag = false // 中间变量
let code = '' // 要返回的code值
if (text_html.indexOf('?') > 0) {
var params = text_html.substring(text_html.indexOf('?') + 1)
if (params) params = params.split('&')
params.forEach(function(p) {
var kv = p.split('=')
if (kv[0] === 'code') {
trag = true
code = kv[1]
}
})
if (trag) {
return code
} else {
return false
}
}
}
第二步:通过code值获取openid
- 进入支付页面时,从路径中获取到code值,去获取openid;
- 注意code有过期时间,当code过期时,需要重新授权获取code,然后再拿新的code值去获取openid;
getWechatOpenId(code) {
// 获取openid
getWechatOpenId(JSON.stringify({
code: code
})).then(res => {
if (res.errcode === 1) {
this.openId = res.openid
}
}).catch(err => {
if (err.errcode === -40) {
// code 过期时,重新授权取code
this.getAuthCode() // 授权获取code
}
})
}
第三步:获取支付参数 唤起微信支付
- 点击微信支付按钮,调后端提供的支付接口,获取微信支付所需参数(公众号名称、时间戳、随机串、订单号、签名方式、签名);
- 在调支付接口成功的回调里直接唤起微信支付(包括判断微信浏览器,并唤起第三方微信支付接口);
- 注: 在WeixinJSBridge.invoke回调里,如果拿到成功状态,是第三方微信返回状态,并不完全可靠,最好和后台配合再次调用内部的支付接口,方可确认支付是否真的完成;
- 支付成功后,跳转指定路由,到达支付成功页面;
goPay(JSON.stringify({ // 调用去支付
openid: this.openId, // 传入openid
pay_order_no: this.orderNum // 传入订单号
}) ) .then(res => {
if (res.errcode === 1) {
// 获取到微信支付参数
this.wei_xin_pay_jssdkvo = res.wei_xin_pay_jssdkvo // 微信支付参数
// 判断是否为微信浏览器,是的话唤起微信支付
if (typeof WeixinJSBridge === 'undefined') {
if (document.addEventListener) {
document.addEventListener(
'WeixinJSBridgeReady',
this.onBridgeReady(this.wei_xin_pay_jssdkvo),
false
)
} else if (document.attachEvent) {
document.attachEvent(
'WeixinJSBridgeReady',
this.onBridgeReady(this.wei_xin_pay_jssdkvo)
)
document.attachEvent(
'onWeixinJSBridgeReady',
this.onBridgeReady(this.wei_xin_pay_jssdkvo)
)
}
} else {
this.onBridgeReady(this.wei_xin_pay_jssdkvo) // 唤起微信支付
}
}
})
onBridgeReady(para) {
// 唤起微信支付
const that = this // 进入微信浏览器时,让this依然指向Vue实例
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
{
appId: para.app_id, // 公众号名称,由商户传入
timeStamp: para.timestamp, // 时间戳,自1970年以来的秒数
nonceStr: para.nonce_str, // 随机串
package: para.prepay_id, // 订单号
signType: para.sign_type, // 微信签名方式
paySign: para.pay_sign // 微信签名
},
function(res) {
if (res.err_msg === 'get_brand_wcpay_request:ok') {
// 使用以上方式判断前端返回,微信团队郑重提示:
// res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
that.payState() // 如果微信返回ok,去获取实际支付状态
} else if (res.err_msg === 'get_brand_wcpay_request:fail') {
// 支付失败的操作
that.$router.replace('/pay-failed')
} else if (res.err_msg === 'get_brand_wcpay_request:cancel') {
// 取消支付的操作
that.$router.replace('/order-center')
}
}
)
}
payState() {
// 支付状态接口
payState(JSON.stringify({
order_no: this.orderNum // 订单号
})).then(res => {
if (res.errcode === 1) {
this.$router.replace('/pay-success')
}
}).catch(err => {
if (err.errcode === -41) {
// 若支付状态为-41,则一直刷新获取支付状态
setTimeout(() => {
this.payState()
}, 3000)
} else {
this.$router.replace('/pay-failed')
}
})
}
结语:本人项目中用的是Vue框架,对axios进行了统一的封装,调用接口时写法上可能与大家存在不一致的地方。在实际项目操作中,大家把接口换成自己可用的,按照自己的书写方式即可!
需要注意的坑:
- alert()函数在微信浏览器中是无法执行的,大家在调试的时候,不要用alert()函数进行调试哦;
- 在WeixinJSBridge.invoke内使用this时,需要注意this指向问题,此时的this指向的是微信浏览器的全局对象;
- 在拿code值获取openid时,注意code是有过期时间的,需要和后端人员配合处理;openid没有过期时间;
到此,一个web端微信支付流程就走完了,欢迎小伙伴们参与讨论,并提出你们的宝贵建议~
刚鼓起勇气开始写博客,希望大佬们不喜勿喷哈~