支付宝 App 支付调用提示 6001 错误如何解决?
结论
6001 是支付宝 App 支付 SDK 返回的客户端状态码,意思是“用户取消支付”。product_code=QUICK_MSECURITY_PAY 是 App 支付的正确取值,不会导致 6001。
如果用户关闭了收银台、点击返回或取消付款,出现这个状态码是正常的。如果用户没有进行任何操作,支付却立即返回 6001,需要检查客户端是否重复发起支付、页面或 Activity 是否提前销毁、支付参数是否经过二次编码,以及 SDK 回调结果是否解析正确。
首先确认返回结果
不要只看弹窗文案,需要记录 SDK 返回的完整结果。典型结构如下:
resultStatus=6001
memo=用户取消
result=
常见的 resultStatus 包括:
| 状态码 | 含义 |
|---|---|
9000 | 支付成功 |
8000 | 正在处理中,最终结果以服务端异步通知或主动查询为准 |
4000 | 支付失败 |
5000 | 重复请求 |
6001 | 用户取消支付 |
6002 | 网络连接异常 |
签名错误、参数错误和权限问题通常不能直接归为“用户取消”。如果页面只显示“6001 错误”,还需要查看 memo、客户端日志和服务端订单状态。
Android 端正确调用方式
服务端生成的完整订单字符串应直接传给 payV2。客户端不要拆分参数、重新排序、重新签名,也不要再次进行 URL 编码。
final String orderInfo = responseFromServer;
Runnable payRunnable = () -> {
PayTask payTask = new PayTask(activity);
Map<String, String> result = payTask.payV2(orderInfo, true);
activity.runOnUiThread(() -> {
String resultStatus = result.get("resultStatus");
String memo = result.get("memo");
String resultData = result.get("result");
Log.d("Alipay", "resultStatus=" + resultStatus);
Log.d("Alipay", "memo=" + memo);
Log.d("Alipay", "result=" + resultData);
if ("6001".equals(resultStatus)) {
// 用户取消,不要按系统故障或支付失败重试
}
});
};
new Thread(payRunnable).start();
需要逐项检查:
orderInfo是否是服务端返回的原始字符串。- 调用前是否执行过
URLEncoder.encode(orderInfo, "UTF-8")。再次编码完整订单字符串会破坏参数。 - 点击一次支付按钮是否触发了多次请求。
- 调用支付时使用的
Activity是否仍然有效。 - 支付期间是否发生页面跳转、
Activity.finish()、进程重启或组件销毁。 - 是否误把 SDK 返回结果中的
memo或其他字段当成状态码。
下面这种处理是错误的:
// 错误:完整订单参数不能再次整体 URL 编码
String encodedOrderInfo =
URLEncoder.encode(orderInfo, StandardCharsets.UTF_8.name());
payTask.payV2(encodedOrderInfo, true);
服务端生成订单参数
签名必须在服务端完成,私钥不能放进 App。使用支付宝服务端 SDK 时,应由 SDK 组装、签名并编码订单字符串。
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do",
appId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setOutTradeNo(outTradeNo);
model.setSubject("支付宝支付订单");
model.setBody("fjreach");
model.setTotalAmount("0.10");
model.setTimeoutExpress("30m");
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl("https://example.com/alipay/notify");
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
String orderInfo = response.getBody();
传给客户端 SDK 的订单字符串应使用 response.getBody()。不要重新拼装其中的参数,也不要重复编码 biz_content、sign 或整个字符串。
如果用户没有取消却立即返回 6001
建议按以下顺序排查。
1. 检查调用次数
为支付按钮添加防重复点击逻辑,并记录每次调用的订单号和时间。如果一次点击调用了两次支付 SDK,后一个流程可能会覆盖或取消前一个流程。
if (!paying.compareAndSet(false, true)) {
return;
}
startAlipay(orderInfo, result -> {
paying.set(false);
handlePayResult(result);
});
还要确保同一个 out_trade_no 不会用不同金额或不同商品信息重复提交。
2. 检查页面生命周期
发起支付后,不要立即关闭承载支付调用的页面:
payTask.payV2(orderInfo, true);
// 不要在这里立即执行
// activity.finish();
如果项目使用 Flutter、React Native、Unity 或其他跨端框架,还要确认原生插件是否正确保存了当前 Activity,以及支付结果是否被多个回调重复消费。
3. 检查参数传输过程
分别记录以下两处的订单字符串:
- 服务端 SDK 生成的字符串。
- 客户端调用
payV2前收到的字符串。
两处字符串应保持一致。常见问题包括:
- JSON 接口传输时,
&被转义或截断。 - 客户端对完整字符串进行了二次 URL 编码。
- 通过表单、路由或 WebView 传参时,
+被转换成空格。 - 日志系统截断了长字符串,让人误以为参数不完整。
- 已经参与签名的字段被手工修改。
不要先在客户端对 sign 执行 URLDecoder.decode(),再把它拼回订单字符串。
4. 检查支付宝客户端与支付 SDK
确认问题是否只出现在某台设备、某个支付宝客户端版本或某个系统版本上。可以进行以下检查:
- 升级到支付宝文档当前推荐的 App 支付 SDK。
- 清理旧 SDK,避免工程中同时存在多个版本。
- 更新支付宝 App 后重新测试。
- 使用不同设备和支付宝账号交叉验证。
- 保留完整的 SDK 返回值和客户端日志,供后续定位。
缺少完整日志时,不能只根据 6001 判断是签名或商户配置错误。
5. 查询服务端订单状态
客户端结果不能作为最终入账依据。即使客户端返回取消、处理中,或者没有收到回调,也要通过异步通知和订单查询确认真实状态。
建议使用:
alipay.trade.query
查询时可以传入商户订单号:
{
"out_trade_no": "zkj2342222"
}
如果查询结果显示订单已经支付成功,应按服务端查询结果处理,不能因为客户端显示 6001 就把已支付订单标记为失败。
示例参数中的另一个问题
示例使用的通知地址是:
http://192.168.0.208:8080/test
这是局域网地址,支付宝服务器通常无法访问。虽然它一般不会导致客户端返回 6001,但会造成服务端收不到异步支付通知。
生产环境应使用公网可访问的 HTTPS 地址,例如:
https://pay.example.com/alipay/notify
通知接口还需要完成验签,并根据 app_id、out_trade_no、total_amount、seller_id 等信息核对订单。处理完成后,按照支付宝接口的要求返回成功响应。
注意事项
QUICK_MSECURITY_PAY无需修改。- 收到
6001时,首先按用户取消处理,不建议自动循环拉起支付。 - 支付是否成功,应以服务端异步通知或
alipay.trade.query查询结果为准。 - 私钥只能保存在服务端,不能写入客户端代码。
- 不要对完整订单字符串进行二次编码。
- 不要通过客户端日志公开完整订单参数。示例中的
app_id、订单号和签名也应作为敏感业务数据管理。 - 再次支付时,可以继续查询原订单状态,也可以根据业务规则生成新的唯一
out_trade_no,避免订单状态混乱。
备注:内容仅供参考。
