最近一直都在弄关于支付的项目,终于是告一段落了,之前也是很想做一下关于支付的项目,终于是接触到了,在这里分享一下
关于支付,暂时只是接触到了微信和支付宝,其他的银联,QQ钱包之类的,应该还要去了解各自的文档和API
先来聊聊 微信支付
微信支付
微信的支付场景有三种,但是支付渠道有两种,这里只简述关于H5前端的部分,原生APP那些的并没有包含
三种支付场景和两种微信支付渠道
微信浏览器打开的网页 –> 微信JSAPI支付
非微信浏览器打开的网页 –> 微信H5支付
微信公众号内的网页 –> 微信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() }) }
|
项目的难点
- 首先就是配置项了,一个项目,难的永远不是代码技术,微信的配置项烦不胜烦,调试的时候又不能在本地运行
- 获取openId时需要跳转页面,此时返回的话,url会停留在微信获取openId的页面,给用户不好的感觉
- 订单超时的问题,由于本地时间与服务器时间存在一定的误差,所以时间需要校准
- 用户重复下单,反复提交支付,支付成功后回到订单页继续支付
返回问题的解决方案如下:
原理大致是这样的,首先获取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)
|
以上就是我对支付的一些理解,如果文章由于我学识浅薄,导致您发现有严重谬误的地方,请一定在评论中指出,我会在第一时间修正我的博文,以避免误人子弟。