首先说明下开发需求,工作外的个人时间接手了一个项目,需要开发微信小程序和h5页面,页面是一样的,所以首次尝试用uniapp开发,一套代码开发同时生成两个端,百度了一天,踩了一堆坑,最后还是按着必要的流程来debug找问题,具体的过程不叙述了,讲几个必要点,没问题可以直接拿,有问题好好读下看看细节哪里出问题吧:
首先是使用同一个支付页面,使用条件编译对应两个端的支付
支付调用方法:
pay() {
let data ={
id:this.menuid,
userId :this.uid
}
let that = this;
const BASE_URL = uni.BASE_URL
// #ifdef MP-WEIXIN
data.channel='X' //区分渠道
uni.request({
url: BASE_URL+接口地址,
data: data,
method:'POST',
success:(res) =>{
if(res.data.code==0){
let paydata=res.data.data.wxPayMpOrderResult
if(paydata.appId==1){
//免费
uni.showToast({
title:'报名成功!'
})
that.fetchData()
}else{
uni.requestPayment({
provider:'wxpay',
timeStamp:String(paydata.timeStamp),
appId:paydata.appId,
nonceStr:paydata.nonceStr,
package:paydata.packageValue,
signType:paydata.signType,
paySign:paydata.paySign,
success: function (res) {
console.log('success:' + JSON.stringify(res));
uni.showToast({
title:'支付成功!'
})
that.fetchData()
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
}
});
}
}else{
uni.showToast({
title:'支付失败!',
icon:'none'
})
}
},
fail:(res)=> {
console.log(res.data);
}
});
// #endif
// #ifdef H5
data.channel='H5'
if (this.$jwx && this.$jwx.isWechat()) {
uni.request({
url: BASE_URL+接口地址,
data: data,
method:'POST',
success:(res) =>{
let _that = that;
if(res.data.code==0){
let paydata=res.data.data.wxPayMpOrderResult
if(paydata.appId==1){
//免费
uni.showToast({
title:'报名成功!'
})
that.fetchData()
}else{
this.$jwx.wxpay(paydata,function (r) {
if (r.errMsg === 'chooseWXPay:ok') {
uni.showToast({
title:'支付成功!'
})
_that.fetchData();
}
});
}
}else{
uni.showToast({
title:'支付失败!',
icon:'none'
})
}
},
fail:(res)=> {
console.log(res.data);
}
});
}
// #endif
}
这里说明下:
这个项目只申请了一个公众号的支付,小程序关联了公众号,所以发起的都是JSAPI支付,本来以为小程序使用JSAPI支付一定要在h5页面唤起,后来发现还是要拿着后端返回的参数回到小程序唤起小程序自带的支付,绕了个弯····因为本来uniapp就可以通过条件编译同一个页面直接唤起小程序的支付了,只要后端给的参数没问题就行,前端就只是拿着参数唤起就行,所以如果失败,不要怀疑,基本是后端的签名问提,因为出于安全考虑前端不写签名逻辑,嚣张点哈哈。
这边还有一个坑,就是h5页面的支付,是要使用jweixin,这里是安装了jweixin-module的依赖,引入到封装方法的js文件并注册到全局变量使用:
js文件部分:
var jweixin = require('jweixin-module');
export default {
//判断是否在微信中
isWechat: function() {
var ua = window.navigator.userAgent.toLowerCase();
if (ua.match(/micromessenger/i) == 'micromessenger') {
console.log('是微信客户端')
return true;
} else {
console.log('不是微信客户端')
return false;
}
},
GetQueryString:function (name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg); //获取url中"?"符后的字符串并正则匹配
var context = "";
if (r != null)
context = r[2];
reg = null;
r = null;
return context == null || context == "" || context == "undefined" ? "" : context;
},
initJssdk:function(callback){
var uri = window.location.href.split('#')[0];
console.log('nowurl'+uri)
let code1 = this.GetQueryString('code')
localStorage.setItem('code',code1)
let code = localStorage.getItem('code')
const BASE_URL = uni.BASE_URL
uni.request({
url:BASE_URL+'be/wx/redirect/js-sdk',
data:{
url:uri
},
method:'POST',
success:(res)=>{
if(res.data.code==0){
let data = res.data.data.wxJsapiSignature;
jweixin.config({
debug: false,
appId: data.appId,
timestamp: data.timestamp,
nonceStr: data.nonceStr,
signature: data.signature,
jsApiList: [//这里是需要用到的接口名称
'updateTimelineShareData',
'updateAppMessageShareData',
'chooseWXPay',//微信支付
]
});
}
if (callback) {
callback(res.data);
}
}
})
},
//微信支付
wxpay: function(data,callback) {
if (!this.isWechat()) {
console.log('不是微信客户端')
return;
}
this.initJssdk(function(res) {
jweixin.ready(function() {
jweixin.chooseWXPay({
timestamp:String(data.timeStamp), // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: data.nonceStr, // 支付签名随机串,不长于 32 位
package: data.packageValue, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
signType: data.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: data.paySign, // 支付签名
success: function (res) {
// console.log(res);
callback(res)
},
fail:function(res){
callback(res)
},
// complete:function(res){
// console.log(res)
// }
});
});
});
}
}
main.js中H5编译条件下注册全局变量
// #ifdef H5
import jwx from '@/request/jwx.js'
Vue.prototype.$jwx = jwx
// #endif
h5支付微信签名校验问题
h5页面支付的时候initJssdk这个方法是必须要的,因为微信会校验h5支付环境,所以需要把h5的地址加到公众号的ip白名单里面并且把完整的url地址传给后端,让后端去生成签名,这个签名是拿来初始化config的,不然开启jweixin的debug就会一直提示什么config:fail、63002,invalid signature、the permission value is offline verifying、{“errMsg”:“chooseWXPay:fail”}等等之类的错误,还有注意初始化的入参、小程序支付的入参、H5支付的入参,一定不要入参写错了。
h5支付出现问题检查步骤:
因为小程序比较简单,后端给的唤起支付的参数没问题,h5就需要好好排查了:
1.确认config正确通过,这是首要的(url、白名单)。
2.写在wx.ready的回调中防止没加载好。
3.确认config的jsApiList参数包含了这个JSAPI。
4.看下微信支付文档,保证支付入参正确,特别大小写问题
5.后端签名正确(公众号和小程序的appId是不一样的)