支付宝 App 支付返回 6001 且无详细错误码
结论
6001 不是 alipay.trade.app.pay 接口返回的业务错误码,而是支付宝客户端 SDK 返回的 resultStatus,表示“用户取消支付”。因此,这类结果通常不会附带 sub_code、sub_msg 等服务端错误信息。
不过,给出的 orderStr 还有两处需要修正或确认:
biz_content缺少 App 支付通常必需的product_code: "QUICK_MSECURITY_PAY"。- 传给客户端支付 SDK 的应该是签名后的参数串,通常不应带有
https://openapi.alipay.com/gateway.do?前缀。建议使用 Node.js SDK 的sdkExec()生成,不要手工拼接网关地址。
仅凭这段 URL 无法判断 RSA2 签名是否正确。验签还需要签名前的原始字符串、应用公钥配置和对应的支付宝公钥。
为什么没有详细错误码
支付宝 App 支付有两类返回结果:
resultStatus:移动端支付 SDK 返回的状态,如9000、6001、6002。code、sub_code:支付宝开放平台接口返回的服务端业务结果。
常见的客户端状态如下:
resultStatus | 含义 |
|---|---|
9000 | 支付成功 |
8000 | 正在处理中 |
4000 | 支付失败 |
6001 | 用户取消支付 |
6002 | 网络连接异常 |
6004 | 支付结果未知,需要查询确认 |
用户在收银台返回、关闭支付页面或取消操作时,客户端可能直接返回 6001。交易此时未必已经进入会产生服务端业务错误的阶段,所以不会有更具体的 sub_code。
因此,6001 没有详细错误码属于正常情况。
orderStr 中需要检查的问题
1. 缺少 product_code
当前 biz_content 解码后为:
{
"out_trade_no": "07E99000221227113937TFA8",
"total_amount": 0.1,
"subject": "购买商品"
}
建议改为:
{
"out_trade_no": "07E99000221227113937TFA8",
"total_amount": "0.10",
"subject": "购买商品",
"product_code": "QUICK_MSECURITY_PAY"
}
total_amount 建议使用保留两位小数的字符串,避免不同语言或序列化库处理浮点数时出现差异。
缺少业务参数通常会引发服务端参数错误,这类错误更可能返回 4000,而不是 6001。因此,这个问题需要修复,但不一定是本次出现 6001 的直接原因。
2. 不要把网关 URL 传给客户端 SDK
App 支付客户端需要的是类似下面的参数串:
app_id=...&biz_content=...&charset=utf-8&method=alipay.trade.app.pay&sign_type=RSA2×tamp=...&version=1.0&sign=...
不是:
https://openapi.alipay.com/gateway.do?method=...
网关地址用于服务端 HTTP API 请求。App 支付的 orderStr 应由服务端 SDK 的 sdkExec() 等方法生成,再原样传给 Android 或 iOS 支付 SDK。
如果当前代码在 sdkExec() 的结果前手工添加了网关地址,需要删除该前缀。
3. 无法通过编码后的 sign 判断签名是否正确
以下情况都可能导致签名失败:
- 使用了错误应用的私钥。
app_id与私钥所属应用不一致。- 开放平台配置的应用公钥与当前私钥不配对。
- 将“支付宝公钥”误当作“应用公钥”上传。
- 签名后又修改了
biz_content、金额或其他参数。 - 参数被重复 URL 编码。
- 客户端接收或传递
orderStr时发生截断。 - RSA2 实际使用的算法不是
SHA256WithRSA。 - 私钥格式或换行处理不正确。
不要尝试通过手工调整参数顺序或编码方式来修复签名。参数排序、签名和 URL 编码应优先交给官方服务端 SDK 处理。
推荐的 Node.js 生成方式
以下示例展示了生成逻辑。具体导入方式需要与项目实际安装的 alipay-sdk-nodejs 版本一致:
const AlipaySdk = require('alipay-sdk').default;
const alipaySdk = new AlipaySdk({
appId: '2021003126642283',
privateKey: process.env.ALIPAY_APP_PRIVATE_KEY,
alipayPublicKey: process.env.ALIPAY_PUBLIC_KEY,
signType: 'RSA2',
gateway: 'https://openapi.alipay.com/gateway.do'
});
async function createAppPayOrder() {
const orderStr = alipaySdk.sdkExec('alipay.trade.app.pay', {
notifyUrl: 'https://example.com/api/alipay/notify',
bizContent: {
outTradeNo: '07E99000221227113937TFA8',
totalAmount: '0.10',
subject: '购买商品',
productCode: 'QUICK_MSECURITY_PAY'
}
});
// 将 orderStr 原样返回给移动端,不要再次拼接网关或重新编码。
return orderStr;
}
不同 SDK 版本可能对 bizContent 中的字段采用驼峰或下划线命名,具体应以当前 SDK 的类型定义和实际文档为准。最终生成的 biz_content 中必须包含:
"product_code": "QUICK_MSECURITY_PAY"
私钥只能保存在服务端,不能放进 App。
客户端应记录完整支付结果
以 Android 为例,应保留支付 SDK 返回的完整结果,不能只记录 resultStatus:
PayTask payTask = new PayTask(activity);
Map<String, String> result = payTask.payV2(orderStr, true);
String resultStatus = result.get("resultStatus");
String resultData = result.get("result");
String memo = result.get("memo");
Log.i("Alipay", "resultStatus=" + resultStatus);
Log.i("Alipay", "result=" + resultData);
Log.i("Alipay", "memo=" + memo);
需要重点检查:
resultStatus是否确实为6001。memo是否包含补充信息。result是否为空。- 传入
payV2()的字符串是否与服务端生成的字符串完全一致。 - 是否调用了两次支付方法。
- 支付页面出现后,是否发生了返回、关闭或 Activity 生命周期变化。
日志可以记录 app_id、out_trade_no、时间和结果状态,但不能记录私钥,也不建议长期完整保存带签名的支付参数。
最可靠的定位方法
第一步:区分客户端取消和接口失败
如果回调为:
resultStatus=6001
并且 result、memo 中没有服务端错误信息,应先按“客户端取消”处理,不必继续寻找并不存在的 sub_code。
如果返回的是:
resultStatus=4000
同时 result 中包含 code、sub_code、msg 或 sub_msg,再根据服务端错误检查参数、签名或应用配置。
第二步:查询订单的最终状态
客户端返回结果不能作为最终入账依据。收到 6001、8000、6002 或 6004 后,可以由服务端调用 alipay.trade.query,使用原来的 out_trade_no 查询交易状态。
const queryResult = await alipaySdk.exec('alipay.trade.query', {
bizContent: {
outTradeNo: '07E99000221227113937TFA8'
}
});
处理方式如下:
- 查询到
TRADE_SUCCESS,或收到验签成功的异步通知时,按支付成功处理。 - 查询到待支付状态时,说明订单尚未完成,可以允许用户重新支付。
- 查询不到交易时,通常表示订单没有成功创建,或没有进入有效支付流程。
- 查询接口返回
code、sub_code时,根据这些服务端错误继续排查。
实际交易状态应以服务端异步通知和主动查询结果为准,不能只依赖客户端返回的 9000 或 6001。
第三步:使用最小参数重新生成订单
排查时不要复用旧的 orderStr,因为其中的时间戳和订单号可能已经失效或重复。每次测试都应:
- 生成新的
out_trade_no。 - 使用当前时间生成签名参数。
- 保留
product_code。 - 使用字符串金额,如
"0.10"。 - 由
sdkExec()一次生成订单串。 - 将结果原样传给客户端,不再编码或拼接字符串。
还需要核对的配置
如果修正订单格式后出现 4000 或明确的服务端错误,再检查以下配置:
app_id是否属于当前应用。- App 支付能力是否已开通并生效。
- 应用公钥与服务端私钥是否配对。
- 使用的支付宝公钥是否属于同一应用和环境。
- 沙箱应用、沙箱网关和沙箱账号是否配套使用。
- 正式环境是否使用正式网关和正式应用配置。
- 签名算法是否为 RSA2。
- 服务端和客户端传递
orderStr时,是否再次执行了encodeURIComponent。
6001 应优先理解为用户取消支付,不一定有可供查询的详细错误码。当前订单参数仍需补充 product_code,同时确认传给 App 支付 SDK 的内容不带网关 URL。修正后,再结合完整的客户端回调、异步通知和 alipay.trade.query 判断交易停在哪个阶段。
备注:内容仅供参考。
