Skip to content

h5 第三方接入(包含支付)

简介

下面是介绍一些 h5 第三方接入问题,包含微信内部支付、微信外部支付、支付宝支付 以及 wx-sdk 的接入和使用

微信支付(外部)

⭐️ 先看微信支付网站,了解支付流程 ⭐️

上面这个是微信支付网站文档,包含各端微信支付, 这里主要记录 h5 的微信支付 (注意: 这里仅支持微信外部的浏览器拉起微信支付中间页, 微信内 h5 支付后面讲 -> 需要通过 wx-sdk 操作)

⭐️h5 的微信支付 详细文档, 前后端的一个流程 ⭐️

h5 的微信支付, 接入方式:开通开发 2 个流程, 这里主要讲开发的流程

下面是 h5 微信支付的一个总流程图

wx=pay

从上面我们可以知道,前端这边主要流程是

  • 用户点击微信支付按钮,发起请求下单
  • 获取到跳转支付的 url 地址
  • 跳转 url 地址
  • 支付完成后跳转结果页

下面用代码展示流程

vue
<template>
  <div class="pay-container">
    <div class="wx-pay" @click="handleWxPay">微信支付</div>
  </div>
</template>

<script>
export default {
  data() {
    return {};
  },
  methods: {
    handleWxUrl(url, callbackResultUrl) {
      if (callbackResultUrl) {
        // 这里必须使用encodeURIComponent编码, 微信要求,
        // 这里可以使用redirect_url在 url 上拼接回调地址, 但是这里会有问题,我们下面说
        url = `${url}&redirect_url=${encodeURIComponent(callbackResultUrl)}`;
      }
      window.location.replace(url);
    },
    handleWxPay() {
      // wxPay 为封装的请求,用于调起微信支付, data为参数
      wxPay(data).then((res) => {
        // 获取到url,用调起微信支付 url
        const { url } = res;
        this.handlePayUrl(url);
      });
    },
  },
};
</script>

在使用微信支付,你可能遇到常见的问题

下面列举一下可能性比较大的问题

  • h5_url 为拉起微信支付收银台的中间页面,可通过访问该 URL 来拉起微信客户端,完成支付,h5_url 的有效期为 5 分钟
  • 微信支付收银台中间页会进行 H5 权限的校验,安全性检查
  • 正常流程用户支付完成后会返回至发起支付的页面,如需返回至指定页面,则可以在 h5_url 后拼接上 redirect_url 参数,来指定回调页面。您希望用户支付完成后跳转至https://www.wechatpay.com.cn,则拼接后的地址为 h5_url= https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx20161110163838f231619da20804912345&package=1037687096&redirect_url=https%3A%2F%2Fwww.wechatpay.com.cn
  • 需对 redirect_url 进行 urlencode 处理
  • 由于设置 redirect_url 后,回跳指定页面的操作可能发生在:
    • 微信支付中间页调起微信收银台后超过 5 秒
    • 用户点击“取消支付”或支付完成后点击“完成”按钮。因此无法保证页面回跳时,支付流程已结束,所以商户设置的 redirect_url 地址不能自动执行查单操作,应让用户去点击按钮触发查单操作,回跳页面展示效果可参考下图 wx=pay

这里的话为因为 redirect_url,无法保证页面回跳时,支付流程已结束, 因此最好的做法是应让用户去点击按钮触发查单操作,回跳页面

可能会发生的错误

官方:可能会发生的错误

支付宝支付(外部)

手机网站支付产品介绍 | 网页&移动应用

支付宝支付的接入方式也分:开通开发 2 个流程

这里我也是主要讲开发的一个流程

老样子, 先看支付宝支付的一个总流程图

ali-pay

跟 h5 微信支付差不多,前端这边主要流程是

  • 用户点击支付宝支付按钮,发起请求下单
  • 获取 form 表单字符串
  • 提交表单调起支付宝支付
  • 支付完成后跳转结果页

下面用代码展示流程

vue
<template>
  <div class="pay-container">
    <div class="wx-pay" @click="handleAliPay">支付宝支付</div>
  </div>
</template>

<script>
export default {
  data() {
    return {};
  },
  methods: {
    handlePayUrl(form, callbackResultUrl) {
      if (callbackResultUrl) {
        // 这里必须使用encodeURIComponent编码
        // 这里可以使用redirect_url在 url 上拼接回调地址,
        // 这里的话最好也是跟h5 微信 支付同样的方式去处理
        //(使用一个弹窗,来查看是否支付成功,是否去跳结果页)
        url = `${url}&redirect_url=${encodeURIComponent(callbackResultUrl)}`;
      }
      window.location.replace(url);
    },
    handleAliPay() {
      // aliPay 为封装的请求,用于调起微信支付, data为参数
      aliPay(data).then((res) => {
        // 获取到 url, 拉起支付宝支付
        const { form } = res;
        this.handlePayUrl(form);
      });
    },
  },
};
</script>

支付宝没微信支付那么多要求, 支付宝可以在开发环境下调起,但是微信支付的话,需要用到绑定的域名

常见的问题, 不过这些问题一般不是前端问题

wx-sdk 注入和使用

微信 sdk 仅用于微信环境内,例如公众号网页

微信 sdk

下面是接入 wx-sdk 的流程

  • 绑定域名
  • 引入 JS 文件
  • 通过 config 接口注入权限验证配置
  • 通过 ready 接口处理成功验证
  • 通过 error 接口处理失败验证

绑定域名

先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS 接口安全域名”。

备注:登录后可在“开发者中心”查看对应的接口权限。

js-safe-domain

这里需要注意的点是:

  • 需要使用公众号登录, 不是用小程序的

引入 JS 文件

在需要调用 JS 接口的页面引入如下 JS 文件,(支持 https):http://res.wx.qq.com/open/js/jweixin-1.6.0.js

如需进一步提升服务稳定性,当上述资源不可访问时,可改访问:http://res2.wx.qq.com/open/js/jweixin-1.6.0.js (支持 https)。

备注:支持使用 AMD/CMD 标准模块加载方法加载

通过 config 接口注入权限验证配置

所有需要使用 JS-SDK 的页面必须先注入配置信息,否则将无法调用(同一个 url 仅需调用一次,对于变化 url 的 SPA 的 web app 可在每次 url 变化时进行调用,目前 Android 微信客户端不支持 pushState 的 H5 新特性,所以使用 pushState 来实现 web app 的页面会导致签名失败,此问题会在 Android6.2 中修复)。

js
wx.config({
  debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
  appId: '', // 必填,公众号的唯一标识
  timestamp: , // 必填,生成签名的时间戳
  nonceStr: '', // 必填,生成签名的随机串
  signature: '',// 必填,签名
  jsApiList: [] // 必填,需要使用的JS接口列表
});

签名算法见文末的附录 1,所有 JS 接口列表见文末的附录 2

注意:如果使用的是小程序云开发静态网站托管的域名的网页,可以免鉴权直接跳任意合法合规小程序,调用 wx.config 时 appId 需填入非个人主体的已认证小程序,不需计算签名,timestamp、nonceStr、signature 填入非空任意值即可。

如果想要在微信网页中使用 wx-sdk, 最需要的是通过 config 接口注入权限,那么如何注入权限呢?

  • 在微信公共平台中拿到 appId, 一般通过服务端接口返回接口, 在这里的话,我主要通过前端的方式去注入,并不会去涉及服务端,也包含 config 后面的参数
  • 生成签名 signature,生成签名的算法在上面

下面我们介绍一下生成签名算法的步骤

  • 生成 jsapi_ticket
  • 生成签名算法

生成 jsapi_ticket 生成签名之前必须先了解一下 jsapi_ticket,jsapi_ticket 是公众号用于调用微信 JS 接口的临时票据。正常情况下,jsapi_ticket 的有效期为 7200 秒,通过 access_token 来获取。由于获取 jsapi_ticket 的 api 调用次数非常有限,频繁刷新 jsapi_ticket 会导致 api 调用受限,影响自身业务,开发者必须在自己的服务全局缓存 jsapi_ticket 。

参考以下文档获取 access_token(有效期 7200 秒,开发者必须在自己的服务全局缓存 access_token):https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html

用第一步拿到的 access_token 采用 http GET 方式请求获得 jsapi_ticket(有效期 7200 秒,开发者必须在自己的服务全局缓存 jsapi_ticket):https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi

生成签名算法

我们已经获取到 jsapi_ticket,之后,通过 微信 js 签名工具 完成签名:

signature
  • jsapi_ticket:通过 getticket 接口获取的 JSAPI 调用凭证(上面)
  • noncestr:随机生成的字符串(上图是 suiyuan --- 随机字符串,可以自己生成)
  • timestamp:当前时间戳(单位:秒)(可以使用 +new Date() 获取)
  • url:需要调用 JS 接口的 URL

接下来通过 config 接口注入权限的代码详细请到这里看:https://gitee.com/igxv/wx-sdk-test/tree/master

核心代码如下

vue
<script setup>
const getUrl = () => {
  alert(location.href.split("#")[0]);
};

// 扫一扫功能
const scanQRCode = () => {
  console.log(22222222);
  wx.scanQRCode({
    needResult: 0, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
    scanType: ["qrCode", "barCode"], // 可以指定扫二维码还是一维码,默认二者都有
    success: function (res) {
      var result = res.resultStr; // 当needResult 为 1 时,扫码返回的结果
    },
  });
};

const injectPermission = () => {
  // 通过请求获取到 appId、timestamp、nonceStr、signature
  wx.config({
    debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
    appId: appId, // 必填,公众号的唯一标识
    timestamp: timestamp, // 必填,生成签名的时间戳
    nonceStr: nonceStr, // 必填,生成签名的随机串
    signature: signature, // 必填,签名
    jsApiList: ["scanQRCode"], // 必填,需要使用的JS接口列表
  });
  // 这里展示扫一扫功能
  wx.ready(function (res) {
    // config信息验证后会执行ready方法,所有接口调用都必须在config接口获得结果之后,config是一个客户端的异步操作,所以如果需要在页面加载时就调用相关接口,则须把相关接口放在ready函数中调用来确保正确执行。对于用户触发时才调用的接口,则可以直接调用,不需要放在ready函数中。
  });
  wx.error(function (res) {
    alert("config信息验证失败", res);
    // config信息验证失败会执行error函数,如签名过期导致验证失败,具体错误信息可以打开config的debug模式查看,也可以在返回的res参数中查看,对于SPA可以在这里更新签名。
  });
};
</script>

<template>
  <div class="btn" @click="getUrl">获取到当前 url</div>
  <div class="btn" @click="injectPermission">注入权限</div>
  <div class="btn" @click="scanQRCode">扫一扫</div>
</template>

<style scoped>
.btn {
  width: 130px;
  height: 30px;
  background-color: skyblue;
  border-radius: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 30px 0;
}
</style>

注入权限后的结果如图

需要注意的是

这里通过函数getUrl 获取到当前 url, 然后对比一下这里校验的 url 是否一致, 如果不一致就会报invalid signature 错误

常见错误及解决方法

常见错误及解决方法,具体看这里

微信支付(内部 / 公众号网页)

⭐️ 接入前的一些准备,必看 ⭐️

方式一:wx-sdk 方法

我们先要把上面的 wx.config的配置改一下, jsApiList 添加 chooseWXPay

js
wx.config({
  debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
  appId: appId, // 必填,公众号的唯一标识
  timestamp: timestamp, // 必填,生成签名的时间戳
  nonceStr: nonceStr, // 必填,生成签名的随机串
  signature: signature, // 必填,签名
  jsApiList: ["chooseWXPay"], // 必填,需要使用的JS接口列表
});

添加后,我们就可以使用 wx.chooseWXPay 去调起支付了,代码如下:

vue
<script setup>
import  wx from 'wx'
const handleWeiXinPay = () => {
  // 先发起请求,获取到相关的 data 数据
  wx.chooseWXPay({          
      appId: data.appId, // 公众号ID,由商户传入
      timeStamp: data.timeStamp, // 时间戳,自1970年以来的秒数
      nonceStr: data.nonceStr, // 随机串
      package: data.package, // // 订单详情扩展字符串
      signType: data.signType, // 微信签名方式
      paySign: data.paySign // 微信签名
      success: (r) => {        
          // 支付成功后的回调函数            
          if (r.errMsg == "chooseWXPay:ok") {                
              //支付成功                    
          } else {                
                //支付失败
          }        
      },    
  });
}
</script>

方式二:JSAPI 支付(WeixinJSBridge.invoke)

官方链接

WeixinJSBridge 内置对象在其他浏览器中无效, 因此我们可以用这个对判断是否在微信环境中, 当然,我们主要是用这个对象调起支付

具体代码如下:

vue
<script setup>
import wx from "wx";
const handleWeiXinPay = () => {
  // 先发起请求,获取到相关的 data 数据
  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(data);
    }
  }
};

const onBridgeReady = () => {
  const _this = this;
  WeixinJSBridge.invoke(
    "getBrandWCPayRequest",
    {
      appId: data.appId, // 公众号ID,由商户传入
      timeStamp: data.timeStamp, // 时间戳,自1970年以来的秒数
      nonceStr: data.nonceStr, // 随机串
      package: data.package, // // 订单详情扩展字符串
      signType: data.signType, // 微信签名方式
      paySign: data.paySign, // 微信签名
    },
    function (res) {
      if (res.err_msg == "get_brand_wcpay_request:ok") {
        // 使用以上方式判断前端返回,微信团队郑重提示:
        //res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
        console.log("成功");
      } else {
        console.log("支付失败,请重新尝试!");
      }
    }
  );
};
</script>

总结

在上面,我们主要介绍了微信支付(包含内部和外部)支付宝支付(外部)wx-wdk 的权限注入和使用,总结一下

微信支付外部

通过接口返回的 url 直接调起微信支付

微信支付内部

  • 通过wx-sdk方法调起支付
  • WeixinJSBridge.invoke

wx-sdk 能调用支付 ,在源代码中就是用了 WeixinJSBridge.invoke 调起的, 所以它们的参数一模一样

支付宝外部支付

跟微信支付外部差不多, 只不过要求没那么高, 在开发环境就可以调起,微信支付外部需要配置好域名才能调起

wx-wdk 的权限注入和使用

通过wx.config注入权限, 然后通过 wx.xx 调起某个方法

注入权限会相对于比较麻烦, 可能遇到挺多坑的,但是按照下面这个,基本可以解决大部分问题

常见错误及解决方法,具体看这里



⭐️⭐️⭐️ 好啦!!!本文章到这里就结束啦。⭐️⭐️⭐️

✿✿ ヽ(°▽°)ノ ✿

撒花 🌸🌸🌸🌸🌸🌸

上次更新于: