h5 第三方接入(包含支付)
简介
下面是介绍一些 h5 第三方接入问题,包含微信内部支付、微信外部支付、支付宝支付 以及 wx-sdk 的接入和使用
微信支付(外部)
上面这个是微信支付网站文档,包含各端微信支付, 这里主要记录 h5 的微信支付 (注意: 这里仅支持微信外部的浏览器拉起微信支付中间页, 微信内 h5 支付后面讲 -> 需要通过 wx-sdk 操作)
h5 的微信支付, 接入方式:开通
和开发
2 个流程, 这里主要讲开发的流程
下面是 h5 微信支付的一个总流程图
从上面我们可以知道,前端这边主要流程是
- 用户点击微信支付按钮,发起请求下单
- 获取到跳转支付的 url 地址
- 跳转 url 地址
- 支付完成后跳转结果页
下面用代码展示流程
<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 地址不能自动执行查单操作,应让用户去点击按钮触发查单操作,回跳页面展示效果可参考下图
这里的话为因为 redirect_url,无法保证页面回跳时,支付流程已结束, 因此最好的做法是应让用户去点击按钮触发查单操作,回跳页面
可能会发生的错误
支付宝支付(外部)
这里我也是主要讲开发的一个流程
老样子, 先看支付宝支付的一个总流程图
跟 h5 微信支付差不多,前端这边主要流程是
- 用户点击支付宝支付按钮,发起请求下单
- 获取 form 表单字符串
- 提交表单调起支付宝支付
- 支付完成后跳转结果页
下面用代码展示流程
<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 仅用于微信环境
内,例如公众号网页
下面是接入 wx-sdk 的流程
- 绑定域名
- 引入 JS 文件
- 通过 config 接口注入权限验证配置
- 通过 ready 接口处理成功验证
- 通过 error 接口处理失败验证
绑定域名
先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS 接口安全域名”。
备注:登录后可在“开发者中心”查看对应的接口权限。
这里需要注意的点是:
- 需要使用
公众号登录
, 不是用小程序的
引入 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 中修复)。
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 签名工具 完成签名:
- jsapi_ticket:通过 getticket 接口获取的 JSAPI 调用凭证(上面)
- noncestr:随机生成的字符串(上图是 suiyuan --- 随机字符串,可以自己生成)
- timestamp:当前时间戳(单位:秒)(可以使用 +new Date() 获取)
- url:需要调用 JS 接口的 URL
接下来通过 config 接口注入权限的代码详细请到这里看:https://gitee.com/igxv/wx-sdk-test/tree/master
核心代码如下
<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
wx.config({
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appId, // 必填,公众号的唯一标识
timestamp: timestamp, // 必填,生成签名的时间戳
nonceStr: nonceStr, // 必填,生成签名的随机串
signature: signature, // 必填,签名
jsApiList: ["chooseWXPay"], // 必填,需要使用的JS接口列表
});
添加后,我们就可以使用 wx.chooseWXPay
去调起支付了,代码如下:
<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 内置对象在其他浏览器中无效, 因此我们可以用这个对判断是否在微信环境
中, 当然,我们主要是用这个对象调起支付
具体代码如下:
<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
调起某个方法
注入权限会相对于比较麻烦, 可能遇到挺多坑的,但是按照下面这个,基本可以解决大部分问题
⭐️⭐️⭐️ 好啦!!!本文章到这里就结束啦。⭐️⭐️⭐️
✿✿ ヽ(°▽°)ノ ✿
撒花 🌸🌸🌸🌸🌸🌸