公司项目须要,须要接入第三方支付,前先后后也搞了好久。虽然微信公众平台文档已经写得很清楚了,可是仍是记录一下整个接入的流程。php
openid
是微信用户在公众号appid
下的惟一用户标识(appid
不一样,则获取到的openid
就不一样,因此不一样的公众号下有不一样的openid
,),可用于永久标记一个用户,同时也是微信公众号支付的必传参数。html
微信支付,须要用户受权,获取code,经过code
获取网页受权,实际上是要取得openid
,须要注意的是,code
只能使用一次,用户每次受权带上的code
都是不同的,而且五分钟内不使用的话会自动过时。前端
咱们在进行支付时,点击支付按钮,首先会跳转了页面而后再跳转回来,而后弹出框让咱们输入密码,支付成功或者支付失败。或者, 没有跳转页面,直接就弹出密码输入框api
上面也说了,咱们获取code
就是为了获取到openid
而后利用openid
这个必传的参数才能成功唤起支付。浏览器
其实呢,让用户每次跳转URL去获取code
,而后传code
参数给后台也是能够的。由于后台的逻辑也是获取了code
以后再利用code
去获取openid
,而后进行进一步的操做。如今只是保存openid
这一操做,从后台放到了前端。 只要咱们前端判断openid
存在,咱们就没必要再跳转URL
进行受权从新获取code
,能够直接进行支付了。微信
因此能够得出下图:app
逻辑图写的虽然并不具体,可是很简要。微信公众平台
接下来咱们就走一遍流程异步
点击支付,第一次支付确定是不存在openid
的,那么就要跳转URL
获取code
官方也已经写得很明白 微信支付网页受权函数
咱们须要拼接此连接:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
其中 APPID
是商户的APPID,REDIRECT_URI
是页面跳转后跳回来的URL
,state
能够放一些咱们自定义的内容,会带在REDIRECT_URI
上。
例如:我要重定向的地址是https://baidu.com/testIndex.html/?#index
那么,我要拼接的地址应该是https://open.weixin.qq.com/connect/oauth2/authorize?appi=XXXXX&redirect_uri=https://baidu.com/testIndex.html/?#index&response_type=code&scope=SCOPE&state={name:guo}#wechat_redirect
(URL
要进行编码encodeURIComponent,这里演示我就省略了)
那么,重点来了,地址根据咱们拼接的地址跳转过去,实际跳转回来的地址会变成:https://baidu.com/testIndex.html?code=XXXX&state={name:guo}/?#index
(一样须要解码decodeURIComponent)
code=XXXX&state={name:guo}
这一坨东西跑到中间去了,那咱们尝试把它取出来放到后面去
变成这样子https://baidu.com/testIndex.html/?#index?code=XXXX&state={name:guo}
这样一来,咱们就能用$route.query
取到参数了
//跳转回来的URL修正,在地址跳转回来的时候调用进行修正 var payUrlReplace = function() { //修正前: http://XXXX/?code=XXX&state=XXX/?#/XXX var codeReg = /(?:[?|&]code=)([\w\d]+)&{0,1}/; var statePayInfoReg= /(?:[?|&]*state=)({{1}.+}{1})&{0,1}/; var url = decodeURIComponent(window.location.href) //这里是为了确保#前有? if (url.indexOf('?#') < 0) { url = url.replace('#','?#'); } var urlReg = /\?#(.+)\?+/ //判断URL挂载参数 if( codeReg.test(url) && statePayInfoReg.test(url) && url.match(statePayInfoReg).length > 0 && url.match(codeReg).length > 0 ){ var code = url.match(codeReg)[1] var state = url.match(statePayInfoReg)[1] url = url.replace(codeReg, '') url = url.replace(statePayInfoReg, '') if (urlReg.test(url)) { url = `${url}&payCode=${code}` }else { url = `${url}?payCode=${code}` } url = `${url}&payInfo=${state}` //修正后变成 http://XXX/?#/XXXX?payCode=XXX&payInfo=XXX,这里我换了字段名 window.location.href = url } }
这样,payCode
和payInfo
都能取到了。
有了code
,就能够获取openid
了,而后存在本地(这里咱们的后台专门写了传code
获openid
的接口,这是异步操做)
上图就说明了咱们传code给后台后,后台再去获取openid
, 后台在传给咱们前端。
而咱们要使用openid请求后台接口获取支付参数就要保证openid
必须存在,获取openid
是异步操做,咱们必须保证前后顺序。值得注意的是,openid一旦获取保存在本地,以后支付就再也不须要获取code了。
//检查是否使用了微信支付 var payIsUse = function(query,callback){ //检查这里是否携带须要支付的参数 //?payCode=XXX&payInfo=XXX if(query && query.payCode){ var code = query.payCode if(query.payInfo){ var payInfo = JSON.parse(query.payInfo) } //判断是否本地存在openID 若是存在则取消回调,由pay方法手动唤起支付 var openID = tokenServer.getOpenId(); if(openID){ return false; } //不存在openID用code去接口请求openID,在触发回调去支付 payModel.saveOpenid({ code:code }).then(function(data){ if( tokenServer.setOpenId(data.data) ){ if(callback){ //将支付参数传给回调函数 具体用的时候是传给pay callback(payInfo) } } } }) } }
后台接口,传参得到的。
https://pay.weixin.qq.com/wik...
//微信JSDK唤起支付 var WeChatJSDKpay = function(config,onSuceess,onError){ var pay = function(){ WeixinJSBridge.invoke('getBrandWCPayRequest',{ "appId":config.appId, "timeStamp": config.timeStamp, "nonceStr": config.nonceStr, "package": config.package, "signType": config.signType, "paySign": config.paySign },function(res){ if(res.err_msg == "get_brand_wcpay_request:ok"){ //支付成功 onSuceess() }else{ //支付失败 onError('支付失败') } }); } if(typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function"){ pay() }else{ if (document.addEventListener) { document.addEventListener("WeixinJSBridgeReady", pay, false); } else if (document.attachEvent) { document.attachEvent("WeixinJSBridgeReady", pay); document.attachEvent("onWeixinJSBridgeReady", pay); } } }
/* *onSuccess 支付成功的回调 *onError 支付失败的回调 *payInfo 支付参数 */ var pay = function(onSuceess,onError,payInfo) { var codeReg = /(?:[?|&]code=)([\w\d]+)&{0,1}/; var statePayInfoReg= /(?:[?|&]*state=)({{1}.+}{1})&{0,1}/; var payCodeReg = /(?:[?|&]payCode=)([\w\d]+)&{0,1}/; var payInfoReg = /(?:[?|&]*payInfo=)({{1}.+}{1})&{0,1}/; var url = decodeURIComponent(window.location.href) var openId = tokenServer.getOpenId() //openid存在 if (openId) { if (!payInfo){ return false; } //整理获取微信支付参数的传参 var defaultParams = { type: 1, //微信浏览器的标志 openId: openId } var _payInfo = tool.extend(defaultParams, payInfo) (第三步骤-请求后台接口获取支付参数) payRequest(_payInfo).then(function(data) { modalLoadingServer.unload(); if(data.appId && data.status === 200){ //第四步骤-调起微信支付JSDK WeChatJSDKpay(data,function(){ //微信JSDK支付成功 返回验证参数-流水号进行验证 onSuceess(data.outTradeNo) },onError) }else{ console.error('获取微信支付参数错误', _payInfo) onError('获取微信支付参数错误,请稍候再试') } }) return false; } //若是已经存在 if(codeReg.test(url) && statePayInfoReg.test(url)){ window.location.reload(); return false; } //重复请求的话 if(payCodeReg.test(url) && payInfoReg.test(url)){ //处理下url从新请求 url = url.replace(payCodeReg,''); url = url.replace(payInfoReg,''); url = encodeURIComponent(url); }else{ //跳转获取code 回调url url = encodeURIComponent(window.location.href); } var statePay = {}; for(var key in payInfo){ //微信内支付不存在回调URL if(payInfo.hasOwnProperty(key) && payInfo[key] && key !== 'returnUrl'){ statePay[key] = payInfo[key] } } var statePay = encodeURIComponent(JSON.stringify(statePay)); var getCodeUrl = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxd9242c6d1e249d25&redirect_uri='+url+'&response_type=code&scope=snsapi_base&state='+statePay+'&connect_redirect=1#wechat_redirect'; //获取`code`的跳转连接 window.location.href = getCodeUrl }
以上是主要的代码逻辑,也不是特别完整可以直接使用,可是可以获得启发。主要仍是要看具体的业务和接口怎么给。有问题欢迎一块儿交流~