h5接入微信支付、支付宝支付、云闪付详解流程

4,806 阅读4分钟

work.webp

由于公司内开发的h5网页需要开始对接多种支付方式(微信支付、h5支付、线下转账、银联转账业务),后续可能还要对接更多方式,目前先总结下微信H5支付方式,由于微信小程序的方式很简单,看文档即可,微信H5支付分为两种情况,1.微信内H5支付 2. 普通浏览器H5微信支付。以前做了支付,但是久都没有做微信支付了,这次就算是记录一下之前的技术债。

1.微信内H5支付业务流程

微信内h5接入流程.jpg

微信内h5网页授权域名配置.drawio.png

    提示:在开发之前最好是配置好对应的授权域名、防止在调试的时候报错

(1).跳转到指定的微信URL获取微信code

window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${redirect_uri}&response_type=code&scope=snsapi_userinfo&state=123#wechat_redirect`;

上述跳转链接参数解释

参数名释义
appid公众号ID
redirect_uri重定向URL,跳转当前URL后,微信会自动跳转你指定的URL地址,并且在地址后面拼接微信code
response_type相应类型,即跳转当前URL地址是为了获取code信息
scope当前值有两种,1.snsapi_userinfo:静默授权,一般微信支付选择静默授权,且用户无感知 2.snsapi_userinfo:需要用户手动点击同意(会有提示框)
state固定值:123#wechat_redirect

(2).通过code获取当前用户的openId,前端可调用后端写的接口获取当前用户的openId

    提示:由于一个手机号在同一个微信公众号里面的openId是固定的,所以此处在获取到openId,可以将当前用户的openId缓存下来,
后面在做支付的时候,直接走openId后面的流程、无须在重新获取openId,可以减少当前用户跳转的步骤,更快的进入支付,
提示需要在当前token失效的时候清除openId,防止当前用户openId错乱

(3).根据openId获取当前微信公众号的配置信息,主要有以下几个参数timeStamp、nonceStr、package、signType、paySign、appId(一般都会返回回来)

(4).拿到上述信息之后,开始最后一步发起微信支付

WeixinJSBridge.invoke('getBrandWCPayRequest', {
    appId: '',
    timeStamp: '',
    nonceStr: '',
    package: '',
    signType: '',
    paySign: ''
}, function(res) {
    if (res.err_msg == 'get_brand_wcpay_request:ok') {
        // 支付成功
    }
    //但是由于上述的判断微信官方文档提示了,并不完全可靠,所以我们通常的做法是跳转到一个新的过渡页面,
    //在过渡页面去轮询当前订单是否已经支付完成,最后跳转到对应的支付成功或者是支付失败的页面
})

2.普通浏览器H5支付业务流程

普通浏览器微信支付.drawio.png

普通浏览器h5微信支付域名配置.drawio.png

    提示:在开发之前最好是配置好对应的授权域名、防止在调试的时候报错

(1).引入微信SDK

1.普通html,可以引入 <script type="text/javascript" src="https://res.wx.qq.com/open/js/jweixin-1.6.0.js"></script>
2.npm 包模块。引入 weixin-js-sdk 包

(2).给当前应用进行微信授权,因为授权涉及到接口需要损耗时间,所以会在进入当前页面或者是更早之前进行用户授权,防止授权微信支付因为未授权导致微信支付失败

wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: '', // 必填,公众号的唯一标识
timestamp: , // 必填,生成签名的时间戳
nonceStr: '', // 必填,生成签名的随机串
signature: '',// 必填,签名
jsApiList: [
    'updateAppMessageShareData',
        'updateTimelineShareData',
        'onMenuShareWeibo',
        'onMenuShareQZone',
        'startRecord',
        'stopRecord',
        'onVoiceRecordEnd',
        'playVoice',
        'pauseVoice',
        'stopVoice',
        'onVoicePlayEnd',
        'uploadVoice',
        'downloadVoice',
        'chooseImage',
        'previewImage',
        'uploadImage',
        'downloadImage',
        'translateVoice',
        'getNetworkType',
        'openLocation',
        'getLocation',
        'hideOptionMenu',
        'showOptionMenu',
        'hideMenuItems',
        'showMenuItems',
        'hideAllNonBaseMenuItem',
        'showAllNonBaseMenuItem',
        'closeWindow',
        'scanQRCode',
        'chooseWXPay',
        'openProductSpecificView',
        'addCard',
        'chooseCard',
    ] // 必填,需要使用的JS接口列表
  },
  wx.error(function(res){
    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开configdebug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
  });
);

(3).调用后端接口进行微信支付,后台接口会返回一个mwebUrl 或者是其他参数名的URl,然后在当前页面重定向到URL,

const currentUrl = encodeURIComponent('需要跳转的URL地址')
window.location.href = `${mwebUrl}` + '&redirect_url=' + currentUrl

3.h5接入支付宝支付

1.直接调用后台的支付接口
const params = {}
alipay(params).then(res => {
    const { data } = res
    if (!data.alipay_trade_wap_pay_response) {
        document.querySelector('body').innerHtml = res.data;
        document.forms[0].submit()
    } else {
        console.log('支付宝支付失败');
        Toast(data.alipay_trade_wap_pay_response.msg)
    }
})

4.h5接入云闪付支付业务流程

h5接入云闪付(银联支付).drawio.png

    // nginx 需要增加如下配置信息
    location /order {
        proxy pass http://xxx:8000/order; proxy method GET;
        proxy redirect default;
        proxy set header X-Real-IP $remote addr; 
        proxy set header X-Scheme $scheme; 
        proxy set header X-Forwarded-For $proxy add x forwarded for; 
        proxy set header Host $proxy host; 
        default type text/html;
     }

(1).隐藏表单信息(表单的信息可能略微有差异,总是使用方式是一样的)

{/*银联支付隐藏Form表单内容*/}
<form id="unionpayForm" method="post">
  <input type="hidden" id="BusiType" name="BusiType" value="" />
  <input
    type="hidden"
    id="CommodityMsg"
    name="CommodityMsg"
    value=""
  />
  <input type="hidden" id="CurryNo" name="CurryNo" value="" />
  <input type="hidden" id="MerBgUrl" name="MerBgUrl" value="" />
  <input type="hidden" id="MerId" name="MerId" value="" />
  <input
    type="hidden"
    id="MerOrderNo"
    name="MerOrderNo"
    value=""
  />
  <input type="hidden" id="OrderAmt" name="OrderAmt" value="" />
  <input type="hidden" id="RemoteAddr" name="RemoteAddr" value="" />
  <input type="hidden" id="Signature" name="Signature" value="" />
  <input type="hidden" id="TranDate" name="TranDate" value="" />
  <input type="hidden" id="TranTime" name="TranTime" value="" />
  <input type="hidden" id="TranType" name="TranType" value="" />
  <input type="hidden" id="Version" name="Version" value="" />
  <input type="hidden" id="PayTimeOut" name="PayTimeOut" value="" />
  <input type="hidden" id="MerPageUrl" name="MerPageUrl" value="" />
</form>
{/*银联支付隐藏Form表单内容*/}

(2).调用后台接口获取信息并且填写到表单里面进行提交

unionPay(params).then(res => {
  console.log('res', res)
  if (res?.code !== 0) {
    Toast.fail('发起云闪付失败,请重试!')
    return
  }
  const data = res.data;
  const payForm = JSON.parse(data.payForm);
  const form = document.getElementById('unionpayForm');
  _this.changeInputValue('BusiType', payForm.BusiType);
  _this.changeInputValue('CommodityMsg', payForm.CommodityMsg);
  _this.changeInputValue('MerBgUrl', payForm.MerBgUrl);
  _this.changeInputValue('CurryNo', payForm.CurryNo);
  _this.changeInputValue('MerId', payForm.MerId);
  _this.changeInputValue('MerOrderNo', payForm.MerOrderNo);
  _this.changeInputValue('OrderAmt', payForm.OrderAmt);
  _this.changeInputValue('RemoteAddr', payForm.RemoteAddr);
  _this.changeInputValue('Signature', payForm.Signature);
  _this.changeInputValue('TranDate', payForm.TranDate);
  _this.changeInputValue('TranTime', payForm.TranTime);
  _this.changeInputValue('TranType', payForm.TranType);
  _this.changeInputValue('Version', payForm.Version);
  _this.changeInputValue('PayTimeOut', payForm.PayTimeOut);
  _this.changeInputValue('MerPageUrl', payForm.MerPageUrl);
  form.action = payForm.url;
  console.log('url', payForm.url);
  // form.target = '_blank';
  form.submit();
})

function changeInputValue (name, value) {
    let tep = document.getElementyId(name)
    tmp.value = value
}

总结: 以上就是我最近做的接入第三方支付的所有内容了,实际上还有一个线下转账,但是这个就是上传图片,然后后台人工审核转账信息,比较简单,所以没有写,希望以后能记录下自己所有想要记录的重要的知识点。

如果我的文章对你有用,请你点个赞,哈哈哈哈哈

努力总会有回报的,加油