移动端的各种支付


最近一直都在弄关于支付的项目,终于是告一段落了,之前也是很想做一下关于支付的项目,终于是接触到了,在这里分享一下

关于支付,暂时只是接触到了微信和支付宝,其他的银联,QQ钱包之类的,应该还要去了解各自的文档和API

先来聊聊 微信支付

微信支付

微信的支付场景有三种,但是支付渠道有两种,这里只简述关于H5前端的部分,原生APP那些的并没有包含

三种支付场景和两种微信支付渠道

  1. 微信浏览器打开的网页 –> 微信JSAPI支付

  2. 非微信浏览器打开的网页 –> 微信H5支付

  3. 微信公众号内的网页 –> 微信JSAPI支付

如果我们移动端的网页是嵌在元素APP里面的,走的也是 微信H5支付,因为内核是谷歌内核,属于非微信浏览器

支付之前需要哪些配置

需要配置的配置项很多,需要进入微信公众号平台进行配置,其中需要注意的有几点
Web端配置的服务器,需要写入ip白名单当中,并且需要通过备案号才可以,商家号也是需要事先注册好的

微信H5支付

我们看看微信H5是怎么实现的

微信H5支付实现起来较为简单,调用后台接口,后台会返回一串微信的URL,跳转URL就可以了

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
// 微信H5支付
wxH5Pay(){
let sendMessage = {
url: this.$api.unifiedPay,
PostData: {
tn: getToken(),
channelId: this.payTypeName
}
}
this.$store.dispatch('Post', sendMessage).then((res) => {
if(res.errorcode !== "0000"){
alert(res.message)
this.$router.replace({
path: '/fail',
query: {
errorcode: res.errorcode
}
})
return ;
}

this.submitName = '确认提交'
window.location.href = res.entity.payParams.payUrl
})
}

支付成功后由于没有回调函数,需要后端配置一个路径,不管成功还是失败,都跳转到中间页去验证订单信息是否成功,重点说一下微信的JSPAI支付

微信JSPAI支付

微信的JSAPI支付较为的繁琐,用户进入页面之前,需要获取用户的openID,因为后台需要这些数据

所以进入页面时,需要先跳转一次连接,通知后台去获取openID,这时候后台会跳转一次连接到微信中,再跳转回我们自己的页面,并且携带openID

1
2
3
4
5
6
7
8
9
10
11
12
// 微信获取openid
getOpenId(){
let sendMessage = {
url: this.$api.getOpenId,
PostData: {
tn: getToken()
}
}
let tnString = encodeURIComponent(sendMessage.PostData.tn)
let url = 'http://*************.com/***/wx/getOpenId?tn=' + tnString + '&redirectUrl=pay'
window.location.href = url
},

支付的时候请求后台接口,将后台需要的参数传递过去,就包括刚刚获取到的openID,来获取我们需要的参数,然后就可以支付了

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
function onBridgeReady() {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": res.entity.payParams.appId, //公众号名称,由商户传入
"timeStamp": res.entity.payParams.timeStamp, //时间戳,自1970年以来的秒数
"nonceStr": res.entity.payParams.nonceStr, //随机串
"package": res.entity.payParams.package,
"signType": res.entity.payParams.signType, //微信签名方式:
"paySign": res.entity.payParams.paySign //微信签名
},
function(res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
_this.queryPayOrderCar()
}else if(res.err_msg == "get_brand_wcpay_request:cancel"){
_this.submitName = '确认提交'
}else if(res.err_msg == "get_brand_wcpay_request:fail"){
_this.queryPayOrderCar()
}else {
_this.queryPayOrderCar()
}

});
}
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
}
} else {
onBridgeReady();
}

这里需要注意的是,支付完成后,我们最后需要去验证一下订单信息到底是否成功支付,微信官方也告诉我们res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。

微信小程序的支付方式和微信JSAPI是一样的,参考上面模板即可,到这里,微信支付告一段落了,看看支付宝的

支付宝支付

支付宝相比较于微信显得简单许多,但是文档不如微信的好阅读

支付之前请求后台接口,获取需要的参数,拼装成from表单后submit提交就可以了,也不用分什么支付宝浏览器还是普通的原生浏览器

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
aliPay(){
let sendMessage = {
url: this.$api.unifiedPay,
PostData: {
tn: getToken(),
channelId: this.payTypeName
}
}

this.$store.dispatch('Post', sendMessage).then((res) => {
if(res.errorcode !== "0000"){
alert(res.message)
this.$router.replace({
path: '/fail',
query: {
errorcode: res.errorcode
}
})
return ;
}

this.submitName = '确认提交'
const div = document.createElement('div')
/* 此处form就是后台返回接收到的数据 */
div.innerHTML = res.entity.payParams.payUrl
document.body.appendChild(div)
document.forms[0].submit()
})
}

项目的难点

  1. 首先就是配置项了,一个项目,难的永远不是代码技术,微信的配置项烦不胜烦,调试的时候又不能在本地运行
  2. 获取openId时需要跳转页面,此时返回的话,url会停留在微信获取openId的页面,给用户不好的感觉
  3. 订单超时的问题,由于本地时间与服务器时间存在一定的误差,所以时间需要校准
  4. 用户重复下单,反复提交支付,支付成功后回到订单页继续支付

返回问题的解决方案如下:

原理大致是这样的,首先获取state,查看是否可以进入页面,如果不可以,说明之前已经携带openId进入过此页了,所以直接返回到上一页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
beforeRouteEnter (to, from, next) {
// 先获取状态,看看能不能进入
let state = sessionStorage.getItem("backState")
if(state){
// 不可以进入,清空sessionStorage并返回商户页面
sessionStorage.clear();
next(vm => {
vm.$router.go(-2)
});
}else{
let openId = to.query.openId
if(!isEmpty(openId)){
// 有openId
sessionStorage.setItem("backState",'no');
}
next()
}
},

超时解决方案如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 获取服务器的时间
var serverTime = res.timeStamp;
// 当前时间的时间戳
var timestamp = new Date().getTime();
// 计算时间差
this.differenceTime = timestamp - serverTime;
// 正 本地时间大于服务器时间

this.lastTime = parseInt((obj.expireTime - (timestamp - this.differenceTime)) / 1000) ;

this.setInterval = setInterval(()=>{
// this.lastTime--
var nowtime = new Date().getTime();
this.lastTime = parseInt((obj.expireTime - (nowtime - this.differenceTime)) / 1000) ;
},1000)

以上就是我对支付的一些理解,如果文章由于我学识浅薄,导致您发现有严重谬误的地方,请一定在评论中指出,我会在第一时间修正我的博文,以避免误人子弟。

-------------本文结束感谢您的阅读-------------