一、问题描述
uniapp对接微信APP支付,本来是很简单的一件事,后端本来就是好的,只要填一些参数就行了,搞了我一晚上,主要卡在uniapp这边,拉起支付的时候,一直提示以下错误:
{
"errMsg": "requestPayment:fail [payment微信:-1]General errors",
"errCode": -100,
"code": -100
}
返回 -1 大部分原因出在包名,签名,和参数部分为空或不对导致的
全网各类关于该错误的教程都看了,最后终于成功解决,-1错误官方的解释如下:APP调起支付 - App支付 | 微信支付商户文档中心
可能得原因还挺多的,并没有详细的错误信息,安全靠猜。
以下问题是来自官方或者网上的解决方法:
uniapp接入v3返回-1 | 微信开放社区
1、使用签名检查工具(https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=20_1)校验签名算法是否有误
2、确认秘钥是否有误(服务商模式使用服务商商户号秘钥,秘钥是在商户平台配置,如果同一商户号调用其它接口成功可排除是秘钥问题)
3、确认接口实际的请求参数与生成签名原串的参数一致,不能增加或缺少参数(可通过打印签名原串进行排查)
4、确认参数的大小写,参数名与接口文档一致
5、签名原串的参数值使用原始值,不需要encode
6、接口需要使用UTF-8编码
7、IOS正常,安卓异常的情况下,请排查包名与包签名
8、未注册APPID
9、项目设置APPID不正确
10、注册的APPID与设置的不匹配
11、服务商模式下,统一下单中的sub_appid是否有传入
12、“唤起支付接口”中的签名类型是否与“统一下单接口”的类型一致
13、微信缓存问题,卸载微信重新安装
14、uni.requestPayment参数大小写问题以及数据为空appid,noncestr,package,partnerid,prepayid,timestamp,sign 都不为空或者不为undefind
15、参数类型(orderInfo)
如果是微信支付,上传参数需要是 Object 对象,而不能是 String 类型。
不然可能只会出现一个加载框,就是不跳转到支付页面。
App端,支付宝支付 orderInfo 为 String 类型。
App端,微信支付 orderInfo 为 Object 类型。
16、是否使用了自己生成的keystore证书,千万别用uniapp的免费证书
二、解决方法
以下是参考微信官方以及网上的一些解决思路,请根据自身问题进行排除,首先从注册以及配置开始,确保前面几步没有错。
微信支付注册以及配置相关
首次开通需要注册两个平台
1.1微信商户
关于V2和V3
1.2微信开放平台
创建APP
按要求填写资料,可参考官方的文档:开发指引 - APP支付 | 微信支付商户文档中心
其中最重要的就是app的包名以及签名
应用包名:是在App项目配置文件AndroidManifest.xml中声明的package值,例如上图中的package="demo.wxpay.tenpay.com"。
应用签名:根据项目的应用包名和编译使用的keystore,可由签名工具生成一个32位的md5串,在调试的手机上安装签名工具后,运行可生成应用签名串,如图所示,绿色串即应用签名。
点击下载签名生成工具
注意:
签名的获取,首先在uniapp里,在打包配置里填写正确的包名已经正式的证书进行打包,参考下面的uniapp准备工作,打包之后进行安装,安装之后通过签名工具获取签名。
应用创建好之后,会得到AppID,AppSecret
默认微信支付是未获得,需要点进去,进行申请
绑定APPID
上面申请成功之后,进入到商户平台,对APPID进行绑定
申请之后,在开放平台中的应用->微信支付->查看详情里->下面有个确认的操作,确认之后就成功的绑定了
uniapp相关配置
使用自有证书进行打包,不要使用测试证书,包名使用自己的如com.xxx.xx,不要使用默认的,默认的是UNI.xxx这种
证书生成参考:Android平台签名证书(.keystore)生成指南
在uniapp配置里配置appid,appid从上面的开放平台获取
上面的几步都设置正确后,下面就先来排查下是服务端的问题还是客户端的问题
服务端排查
1.确认appId,mchId,秘钥这些都没问题
我这里服务端用的是JAVA,用的是官方的SDK:SDK - SDK&开发工具 | 微信支付商户文档中心
该SDK仅支持V3,所以这里以V3来演示,app支付相关代码
package xxxx;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.app.AppServiceExtension;
import com.wechat.pay.java.service.payments.app.model.PrepayRequest;
import com.wechat.pay.java.service.payments.app.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
/** APP 支付下单为例 */
public class QuickStart {
/** 商户号 */
public static String merchantId = "1654xxxx";
/** 商户API私钥路径 */
public static String privateKeyPath = "D:\\idea_work\\cert\\apiclient_key.pem";
/** 商户证书序列号 */
public static String merchantSerialNumber = "5DFCB4FD7930CCxxxxxx";
/** 商户APIV3密钥 */
public static String apiV3Key = "xxxxxxxxx";
public static void main(String[] args) {
// 使用自动更新平台证书的RSA配置
// 一个商户号只能初始化一个配置,否则会因为重复的下载任务报错
Config config =
new RSAAutoCertificateConfig.Builder()
.merchantId(merchantId)
.privateKeyFromPath(privateKeyPath)
.merchantSerialNumber(merchantSerialNumber)
.apiV3Key(apiV3Key)
.build();
// 构建service
//AppService service = new AppService.Builder().config(config).build();
AppServiceExtension service = new AppServiceExtension.Builder().config(config).build();
// request.setXxx(val)设置所需参数,具体参数可见Request定义
PrepayRequest request = new PrepayRequest();
Amount amount = new Amount();
amount.setTotal(100);
com.wechat.pay.java.service.payments.app.model.Amount amount1 = new com.wechat.pay.java.service.payments.app.model.Amount();
amount1.setTotal(1);
amount1.setCurrency("CNY");
request.setAmount(amount1);
request.setAppid("wx9xxxx");
request.setMchid("1654xxxx");
request.setDescription("测试商品标题");
request.setNotifyUrl("https://notify_url");
request.setOutTradeNo("out_trade_no_001");
// 调用下单方法,得到应答
PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
String signStr = String.format("%s\n%s\n%s\n%s\n", response.getAppid(), response.getTimestamp(), response.getNonceStr(), response.getPrepayId());;
System.out.println(JsonUtils.toJsonString(response));
System.out.println(response.getPrepayId());
System.out.println(response.getSign());
}
}
如果上面的代码成功执行,会返回如下:
{
"appid":"wx9f3ab2xxxx",
"partnerId":"1654254xxx",
"prepayId":"wx2713xxxx5571830b157fc3001af10000",
"packageVal":"Sign=WXPay",
"nonceStr":"B4PHQp7axxQ6IeTVTuz5SPXxgA7H1Kf3",
"timestamp":"1695793306",
"sign":"I6+ZhY/0r8bjJxs+c092oIOTRZpeSl9fAUi6jAWt8n71s4tld41LNOveOePIT6Jca9CW9KWl6Bonx4U610LQlK0SdO5BVXuf8P3A3dixxxx"
}
这样就能确认appId,mchId,秘钥这些都没问题,如果有签名相关的错误,可按如下进行操作。
2.V2和V3验签验证
V2工具:微信支付接口签名校验工具
如果使用的是V2版本,具体可参考:全网最全v2接口签名报错排查指引!!!! | 微信开放社区
可通过该工具生成支付参数:
然后直接使用postman进行请求测试,不需要什么配置,只要参数跟请求的url
也可以通过该工具对参数进行校验
V3工具:验签工具 - SDK&开发工具 | 微信支付商户文档中心
如果使用的是V3版本,下单时的签名规则如下:APP调起支付 - App支付 | 微信支付商户文档中心
注意签名验签工具明文,最后一行有个换行符。
客户端排查
如果上面返回的数据没问题,基本上可以确认就是客户端这边的问题了,客户端这边可以从下面几个方面来排查:
1.是否使用自定义基座运行,不支持直接通过标准基座调试运行
2.app包名以及签名是否正确
通过上面的自定义基座或者打包出来的app,安装到手机上之后,通过上面的签名工具,输入包名再次确认下签名是否正确
3.uniapp是否正确的配置appid
4.uni.requestPayment参数大小写是否正确以及参数是否为空
官方的代码:uni.requestPayment(OBJECT) | uni-app官网
uni.requestPayment({
"provider": "wxpay",
"orderInfo": {
"appid": "wx499********7c70e", // 微信开放平台 - 应用 - AppId,注意和微信小程序、公众号 AppId 可能不一致
"noncestr": "c5sEwbaNPiXAF3iv", // 随机字符串
"package": "Sign=WXPay", // 固定值
"partnerid": "148*****52", // 微信支付商户号
"prepayid": "wx202254********************fbe90000", // 统一下单订单号
"timestamp": 1597935292, // 时间戳(单位:秒)
"sign": "A842B45937F6EFF60DEC7A2EAA52D5A0" // 签名,这里用的 MD5/RSA 签名
},
success(res) {},
fail(e) {}
})
特别要注意这里:
1.orderInfo是个对象不是字符串,
2.里面的参数要仔细对比下,看下自己的是不是一致,如果直接用后台返回的参数填进去,后台返回的参数有些是大写,会导致参数不一致。
3.参数不能为空,都要有值
三、相关问题
网上有人说,微信app支付,不支持真机调试,只能打包成app安装进行测试,经测试,通过基座打包进行调试可以拉起支付。
网上有人说uniapp只支持v2,经测试,同时支持v2和v3,调用requestPayment接口即可,不需要改其他任何东西
uni.requestPayment({
"provider": "wxpay",
"orderInfo": {
"appid": "wx499********7c70e", // 微信开放平台 - 应用 - AppId,注意和微信小程序、公众号 AppId 可能不一致
"noncestr": "c5sEwbaNPiXAF3iv", // 随机字符串
"package": "Sign=WXPay", // 固定值
"partnerid": "148*****52", // 微信支付商户号
"prepayid": "wx202254********************fbe90000", // 统一下单订单号
"timestamp": 1597935292, // 时间戳(单位:秒)
"sign": "A842B45937F6EFF60DEC7A2EAA52D5A0" // 签名,这里用的 MD5/RSA 签名
},
success(res) {},
fail(e) {}
})