场景是用户通过微信扫app内的收款码,跳到一个h5页面。然后完成支付。
代码实现的整体流程:
使用微信扫码,码是app内生成的,码的内容是一个h5页面链接,扫码完成后跳转到自定义的h5支付界面。
扫码进入后,将页面展示所需要的参数进行缓存起来,存到本地。 然后需要微信静默授权。
- 微信静默授权的流程:
配置appid、redirect_uri等参数,从项目页面跳转到微信授权页面:
https://open.weixin.qq.com/connect/oauth2/authorize
详细参考[ 微信官方文档]open.weixin.qq.com/connect/oau…
参数说明
参数名 | 是否必须 | 说明 |
---|---|---|
appid | 是 | 公众号的唯一标识 |
redirect_uri | 是 | 授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理 |
response_type | 是 | 返回类型,请填写code |
scope | 是 | 应用授权作用域,snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid),snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 ) |
state | 否 | 重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节 |
#wechat_redirect | 是 | 无论直接打开还是做页面302重定向时候,必须带此参数 |
forcePopup | 否 | 强制此次授权需要用户弹窗确认;默认为false;需要注意的是,若用户命中了特殊场景下的静默授权逻辑,则此参数不生效 |
// 示例
let ua = window.navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == 'micromessenger') {
// 回调地址:域名加页面路径
let hdurl = encodeURIComponent('https://.../#/page_wallet');
let appId = '申请项目的appid';
window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${hdurl}&response_type=code&scope=snsapi_base#wechat_redirect`;
}
- 当授权后,会自动跳转到配置回调页面,也就是配置的‘redirect_uri’ 相当携带这code,重新打开了项目
- 然后解析url中的code,将code取出,支付的时候将code传给后端。
点击支付的时候,请求接口,使用微信浏览器内置对象WeixinJSBridge
调起微信支付,使用方法如下所示,data就是由后端返回的数据。
function onBridgeReady(data) {
WeixinJSBridge.invoke(
"getBrandWCPayRequest",
{
// 公众号名称,由商户传入
appId: data.appId,
// 时间戳,自1970年以来的秒数
timeStamp: data.timeStamp,
// 随机串
nonceStr: data.nonceStr,
package: data.package,
// 微信签名方式:
signType: "MD5",
// 微信签名
paySign: data.paySign,
},
function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
// 使用以上方式判断前端返回,微信团队郑重提示:
// res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}
}
)
}
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();
}
在使用uniapp开发中使用的代码如下:
<template>
<view v-show="show">
...内容省略
<view @click="confirmPay">付款</view>
</view>
</template>
<script>
// 支付接口
import { payment_code } from '@/api/wallet';
export default {
data() {
return {
show: true, // 控制页面展示
user: {}, // 页面信息
form: { price: '', type: 0, code: null, receiver_id: null }, // 提交参数
paydata: {} //返回的支付信息
};
},
onLoad(e) {
// 扫码后第一次进入该页面时
if (e.id) {
this.user = {
name: e.name,
id: e.id,
};
this.form.receiver_id = e.id;
// 将信息存到本地
uni.setStorageSync('userpay', this.user);
}else{
// 第二次进入(授权成功后,通过回调进入的页面)
let data = uni.getStorageSync('userpay');
this.user = {
name: data.name,
id: data.id,
};
this.form.price = data.price;
this.form.receiver_id = data.id;
let ua = window.navigator.userAgent.toLowerCase();
//判断是不是微信
if (ua.match(/MicroMessenger/i) == 'micromessenger') {
// 第二次进来时,路径上已经携带了code,获取code。
this.form.code = this.getUrlParam('code');
}
}
// 去授权
this.goAuthorization()
},
methods:{
// 授权方法
goAuthorization(){
let ua = window.navigator.userAgent.toLowerCase();
// //判断是不是微信
if (ua.match(/MicroMessenger/i) == 'micromessenger') {
// 判断是否已经获取了code
if (this.form.code == null || this.form.code === '') {
// 如果还没有code,就跳转授权页面
let hdurl = encodeURIComponent('https://.../#/page_wallet');
let appId = '申请项目的appid';
window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${hdurl}&response_type=code&scope=snsapi_base#wechat_redirect`;
}else{
// 有code的话,就将页面内容显示出来
this.show = true;
}
}
}
},
// 点击支付后,调用
confirm(e) {
uni.showLoading({});
uni.$u.http.post('支付接口',this.form).then(res=>{
uni.hideLoading();
// 将返回的data赋值
this.paydata = res.data.data;
let that = this;
// 绑定事件
if (typeof WeixinJSBridge == 'undefined') {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', that.wxonBridgeReady, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', that.wxonBridgeReady);
document.attachEvent('onWeixinJSBridgeReady', that.wxonBridgeReady);
}
} else {
this.wxonBridgeReady();
}
}).catch((err) => {
// 如果接口调用失败了,将信息存起来,再走一遍授权。
this.user.price = this.form.price;
uni.setStorageSync('userpay', this.user);
this.form.code = null;
this.goAuthorization();
});
},
// 微信支付
wxonBridgeReady(){
let that = this;
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
{
appId: that.paydata.appId,
timeStamp: that.paydata.timeStamp,
nonceStr: that.paydata.nonceStr,
package: that.paydata.package,
signType: that.paydata.signType,
paySign: that.paydata.paySign
},
function (res) {
// 如果取消了支付,就关闭当前h5页面,直接返回微信,也可以进行其他操作,通过res.err_msg来判断即可
if (res.err_msg == 'get_brand_wcpay_request:cancel') {
//关闭当前浏览器
WeixinJSBridge.call('closeWindow');
}
// 这里是支付成功
if (res.err_msg == 'get_brand_wcpay_request:ok') {
// 使用以上方式判断前端返回,微信团队郑重提示:
//res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
}
}
)
},
// 获取路径上参数的方法,用于获取code
getUrlParam(name) {
const url = window.location.href;
const queryString = url.split('?')[1];
if (!queryString) return null;
const params = queryString.split('&');
for (const param of params) {
const [key, value] = param.split('=');
if (key === name) {
return decodeURIComponent(value);
}
}
return null;
},
}
</script>
这篇和另一篇支付宝内置h5支付其实是差不多的,为了避免混乱我分开了,有兴趣的可以查看另一篇支付宝内置H5支付
有什么疑问,欢迎讨论和私信。我会及时回复