微信支付全流程实现--踩过的坑

微信支付所经历的流程:

  • 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端微信支付流程就走完了,欢迎小伙伴们参与讨论,并提出你们的宝贵建议~
刚鼓起勇气开始写博客,希望大佬们不喜勿喷哈~

发布了54 篇原创文章 · 获赞 22 · 访问量 7214

猜你喜欢

转载自blog.csdn.net/Riona_cheng/article/details/97915027