目录
前言
问题
支付场景非法或请在微信外打开订单
微信公众号支付 错误chooseWXPay:fail, the permission value is offline verifying
其他支付对接方式
H5微信支付
支付宝支付
支付各环境测试情况
写在最后
这次项目是基于react写的一个h5,但是后期改成了SDK的形式,打包工具用的webpack;总的来说遇到了不少问题,解决的时候一度挠秃头。毕竟挂钩是否能提前转正,碍于面子总想着加班提前完成,费了不少精力,好在是终于完成了,松了口气~
对于这次项目遇到的问题就分模块写几篇记录,这篇是支付遇到的问题~
首先说明,本人技术仅高于菜鸟一级~文章倾向于大白话风格,写的若是有什么不对的地方欢迎指正~(希望不要批评我哈哈哈~*✧⁺˚⁺ପ(๑・ω・)੭ु⁾⁾ )也欢迎补充(*^▽^*)~
解决方法
区别环境使用不同的微信API。
首先遇到的一个坑就是不同环境下的支付需要调用不同的API类型。
例如我这次的项目有两种支付环境,可以区分为微信环境和非微信环境。因此,对应就需要用到下图中的JSAPI支付和H5支付。
微信支付开发文档的截图原来我都是按H5写,调用支付的时候就自己想当然的使用H5支付。于是在微信环境内测试就出现了如下问题。
H5支付文档中的常见问题5微信H5支付文档中的常见问题的确很实用,遇到的错误都可以再这里找到问题原因。
既然说是H5支付不能再微信客户端内调起,那么就只能换一个了,于是我仔细看了下文档才发现微信环境内调用是需要使用JSAPI的 。
JSAPI使用比较简单,前面基本的设置,JSAPI支付文档已经写的很清楚了,后面的调用也都是由后端调用。
后端注意交易类型的区分:trade_type=MWEB(H5支付)trade_type=JSAPI(JSAPI支付)否则会报支付场景非法。
前端判断代码:
// 示例代码来源于官方文档
function onBridgeReady(){
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId":"wx2421b1c4370ec43b", //公众号名称,由商户传入
"timeStamp":"1395712654", //时间戳,自1970年以来的秒数
"nonceStr":"e61463f8efa94090b1f366cccfbbb444", //随机串
"package":"prepay_id=u802345jgfjsdfgsdg888",
"signType":"MD5", //微信签名方式:
"paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名
},
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();
}
getBrandWCPayRequest参数可以全部由后端返回。前端只需要调用WeixinJSBridge内置对象和判断返回结果即可。具体要仔细研读文档。
// 判断是否是微信环境的代码
var isWechart = function () {
var rst = true
if(window.navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)){
var ua = navigator.userAgent.toLowerCase();
if (!(ua.match(/MicroMessenger/i) == "micromessenger")) {
rst = false;
}
}else {
rst = false;
}
return rst;
}
/* ------------------- 其他 js判断浏览器的环境代码 --------------------------*/
/* 参考链接:https://www.jb51.net/article/178066.htm */
// 判断微信浏览器是PC端还是手机端,以及手机端是微信浏览器还是非微信浏览器
//平台、设备和操作系统
var system = {
win: false,
mac: false,
xll: false,
ipad: false
};
//检测平台
var p = navigator.platform;
system.win = p.indexOf("Win") == 0;
system.mac = p.indexOf("Mac") == 0;
system.x11 = (p == "X11") || (p.indexOf("Linux") == 0);
system.ipad = (navigator.userAgent.match(/iPad/i) != null) ? true : false;
//跳转语句,如果是手机访问就自动跳转到wap.baidu.com页面
if (system.win || system.mac || system.xll || system.ipad) {
alert("在PC端上打开的");
} else {
var ua = navigator.userAgent.toLowerCase();
if(ua.match(/MicroMessenger/i)=="micromessenger") {
alert("在手机端微信上打开的");
} else {
alert("在手机上非微信上打开的");
}
}
// 判断浏览器函数
// 方法一
function isMobile(){
if(window.navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)) {
return true; // 移动端
}else{
return false; // PC端
}
}
// 方法二摘自:im.qq.com
var os = function() {
var ua = navigator.userAgent,
isWindowsPhone = /(?:Windows Phone)/.test(ua),
isSymbian = /(?:SymbianOS)/.test(ua) || isWindowsPhone,
isAndroid = /(?:Android)/.test(ua),
isFireFox = /(?:Firefox)/.test(ua),
isChrome = /(?:Chrome|CriOS)/.test(ua),
isTablet = /(?:iPad|PlayBook)/.test(ua) || (isAndroid && !/(?:Mobile)/.test(ua)) || (isFireFox && /(?:Tablet)/.test(ua)),
isPhone = /(?:iPhone)/.test(ua) && !isTablet,
isPc = !isPhone && !isAndroid && !isSymbian;
return {
isTablet: isTablet,
isPhone: isPhone,
isAndroid : isAndroid,
isPc : isPc
};
}();
// 使用方法
if(os.isAndroid || os.isPhone){
alert("-----");
}
为了方便测试我开了微信开发者工具的公众号网页来测试,普通功能是没问题的,调支付接口的话就会报错。
有两种可能,一种是非真机调用引起的,一种是url地址错误。
解决方法
一是在模拟器中实行发起支付,要在真机是发起
二是微信公众号支付授权目录要填写实际发起支付的url地址,比如你的页面是http://www.newfms.com/order/pay/id-115,那么此处应该填http://www.newfms.com/order/pay/
参考链接:https://blog.csdn.net/haibo0668/article/details/85209238
h5微信支付调用比较简单,由后端调统一下单接口,返回一个url地址,前端只需要跳转这个url就行。
支付宝的也很简单,由后端发起订单请求,根据返回的订单数据来拉起支付宝支付。
我采用的是form提交。
let temp = document.createElement("form");
temp.action = res.action;
temp.method = res.method;
temp.style.display = "none";
let params = res.para;
for (const k in params) {
let opt = document.createElement("input");
opt.name = k;
opt.value = params[k];
temp.appendChild(opt);
}
document.body.appendChild(temp);
temp.submit();
// 参考链接: https://www.cnblogs.com/jun-qi/p/12313495.html
最后走通流程测试后,发现支付宝支付有个问题, form表单调用支付宝会跳转到H5收银台页面然后再调起跳转到支付宝APP,在取消支付后回来,H5收银页无法关闭。
至此开始走了不少弯路。。。
首先是写了iframe,让H5收银页显示在iframe中,再额外手动写个关闭按钮放上去。
解决了H5收银页关闭的问题,出现了另一个问题,在IOS中,iframe无法调起支付宝APP,并且在安卓中也需要用户手动点击蓝色的【使用支付宝APP付款】的按钮才可以跳转,并不是自动跳转。
除此之外前前后后还试了不少方法,看了几遍文档,无奈后端小哥哥太忙,没有时间配合我做其他方法的测试。最后好歹是发现了控件跳转这个方法(其实也在文档中)。
但是这个方法前端并不用做什么事情,我查过收银页的代码,发现跳转的代码是写在这里的,并且也有打印出来,只是我无法获取到,于是改由后端去访问,再返回已经拼接好的(以alipay:// 或 alipays:// 开头的)跳转链接,前端只需要重定向到这个链接就能不跳转收银页调起支付宝APP了。
大致测试结果如图,由于是我项目完成后总结回忆的,并且安卓的测试情况由后端小哥哥提供,所以可能有偏差,欢迎指正~
项目要求是微信环境下不设支付宝支付,所以“ - ” 都是不需要测试的情况,仅使用微信JSAPI即可。
最终出了微信环境下微信支付,其他项目全部采用控件调起APP支付,微信控件支付同支付宝调起类似,也是后端返回拼接好的以weixin:// 开头的跳转链接,重定向即可。但是如上图所示,可以看出在IOS中会出现支付完成或取消后跳转QQ浏览器的页面。不大清楚有没有自身错误操作的原因,但是最终没找到问题,卸载QQ浏览器后也不是跳到IOS默认浏览器Safari中,而是直接关闭支付弹窗,需要像支付宝一样手动返回自己的网站或者网页。
支付功能一度被我放在项目进度后面的后面,但是其实了解了后就觉得也没有很棘手,官方文档还是要好好看~看多几个人家写的demo就差不多啦~