在开发UniApp应用的支付功能时,我们通常会先使用支付宝沙箱环境进行测试,避免在真实环境中频繁发起测试交易。但很多开发者可能会遇到一个令人头疼的问题:明明参数看起来都正确,却总是提示"商家订单参数异常,请重新发起付款",接着报出一堆看不懂的错误代码。今天,我就来分享一下我踩过的坑和最终的解决方案。
1. 问题描述
在我们使用UniApp开发的安卓App中集成支付宝支付功能时,按照官方文档配置了参数,后端也返回了支付字符串,但在沙箱环境下总是遇到以下错误:
{
"errMsg": "requestPayment:fail [payment支付宝:62009]未知错误",
"errCode": -100,
"code": -100
}
同时,支付宝APP上会弹出提示:"商家订单参数异常,请重新发起付款。"
2. 排查过程
2.1 检查uni.requestPayment参数
首先我查看了uni.requestPayment的调用参数,按照官方文档,支付宝支付只需要两个参数:
uni.requestPayment({
provider: 'alipay',
orderInfo: 'orderInfo', // 后端返回的支付宝订单数据
success: function (res) {
console.log('success:' + JSON.stringify(res));
},
fail: function (err) {
console.log('fail:' + JSON.stringify(err));
}
});
2.2 验证支付字符串
我怀疑是后端返回的orderInfo字符串有问题,于是进行了客户端调试:
- 复制了后端返回的订单字符串
- 使用支付宝官方提供的工具验证签名
- 确认orderInfo内容格式无误
甚至在正式环境中,使用相同的调用方式和类似的参数是可以正常支付的。
3. 解决方案揭秘
经过反复测试和查阅资料,我终于发现了问题所在:在支付宝沙箱环境中,我们需要特别设置SDK的环境变量!
3.1 关键代码
在调用支付前,需要添加以下关键代码:
// 导入支付宝SDK的环境工具类
var EnvUtils = plus.android.importClass('com.alipay.sdk.app.EnvUtils');
// 设置为沙箱环境
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
就是这短短两行代码,解决了困扰许久的问题!
3.2 完整的实现方案
下面是一个更完整、更健壮的支付宝支付方法实现:
/**
* 启动支付宝支付流程
* @param payOrderInfo 支付字符串
* @param isSandbox 是否沙箱环境
* @param callbacks 回调函数集合
*/
static startAlipayPayment(
payOrderInfo: string,
isSandbox: boolean,
callbacks: {
onSuccess?: (result: any) => void;
onFail?: (error: any) => void;
} = {}
): void {
const { onSuccess, onFail } = callbacks;
console.log('最终支付字符串:', payOrderInfo);
console.log('环境类型:', isSandbox ? '支付宝沙箱环境' : '支付宝正式环境');
// #ifdef APP-PLUS
// 如果是沙箱环境,需要配置支付宝SDK的环境变量
if (isSandbox) {
try {
console.log('配置支付宝SDK为沙箱环境');
// 导入支付宝SDK的环境工具类
// @ts-ignore
var EnvUtils = plus.android.importClass('com.alipay.sdk.app.EnvUtils');
// 设置为沙箱环境
// @ts-ignore
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
console.log('支付宝SDK环境配置成功');
} catch (error) {
console.error('配置支付宝SDK环境失败:', error);
}
}
// #endif
// 调用支付
uni.requestPayment({
provider: 'alipay',
orderInfo: payOrderInfo,
success: function(result) {
if (onSuccess) onSuccess(result);
},
fail: function(err) {
if (onFail) onFail(err);
// 如果是取消支付,不尝试二次支付
if (!err.errMsg?.includes('62001')) {
// 尝试使用另一种方法重新唤起支付
setTimeout(() => {
// 如果传统方法失败,尝试提前解码再传递
const decodedOrderInfo = decodeURIComponent(payOrderInfo);
console.log('解码后重试支付字符串:', decodedOrderInfo);
// #ifdef APP-PLUS
// 二次尝试前重新配置沙箱环境
if (isSandbox) {
try {
// @ts-ignore
var EnvUtils = plus.android.importClass('com.alipay.sdk.app.EnvUtils');
// @ts-ignore
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
} catch (error) {
console.error('二次尝试配置沙箱环境失败:', error);
}
}
// #endif
uni.requestPayment({
provider: 'alipay',
orderInfo: decodedOrderInfo,
success: function(result) {
console.log('二次尝试支付成功:', result);
if (onSuccess) onSuccess(result);
},
fail: function(e) {
console.error('二次尝试也失败:', e);
// 这里不再调用失败回调,因为第一次失败已经调用了
}
});
}, 500);
}
}
});
}