使用 apipay.sdkExecute 和 orderStr 支付返回 6001
结论
支付宝 APP 支付返回 resultStatus=6001,通常表示用户取消了支付,比如关闭收银台、按下返回键,或者支付流程被系统中断。这个状态码并不直接表示“缺少必传参数”或“签名验证失败”。
当前 APPID 的交易额度为 0 元,显然无法满足正常交易条件。建议先解除额度限制,或换用能够正常交易的 APPID,再继续测试。现有信息不足以判断额度为 0 元 是否会直接触发 6001,还需要查看支付宝客户端的实际页面和服务端交易记录。
建议按以下顺序排查
1. 确认完整返回结果
不要只记录 6001,还要保存 resultStatus、result 和 memo:
Map<String, String> result = new PayTask(activity).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);
常见状态的含义如下:
9000:订单支付成功。8000:结果确认中,需要通过服务端异步通知或订单查询确认。6001:用户取消支付。6002:网络连接异常。4000:支付失败。
客户端状态只适合用于界面提示。最终支付结果必须以支付宝异步通知或服务端查询结果为准。
2. 先处理额度为 0 的问题
APPID 即使已经开通 APP 支付,交易额度为 0 元 时,实际支付仍可能受到商户状态、风控、签约状态或产品权限的限制。
请在支付宝开放平台或商家后台检查:
- APP 支付产品是否已经正式签约并生效;
- APPID 与签约主体是否对应;
- 商户账户是否存在额度、风控或账户状态限制;
- 当前使用的是正式环境还是沙箱环境;
- APPID、网关、密钥和支付宝客户端环境是否属于同一套环境。
额度限制解除前,不建议继续用这个 APPID 判断支付代码是否正常。
3. 检查 orderStr 是否被二次处理
服务端应直接把 sdkExecute() 返回的内容作为 orderStr:
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.setSubject("测试订单");
model.setOutTradeNo(outTradeNo);
model.setTotalAmount("0.01");
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl(notifyUrl);
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
if (!response.isSuccess()) {
throw new IllegalStateException(
"生成支付订单失败:code=" + response.getCode()
+ ", subCode=" + response.getSubCode()
+ ", msg=" + response.getMsg()
+ ", subMsg=" + response.getSubMsg()
);
}
String orderStr = response.getBody();
客户端收到订单串后,直接调用:
PayTask alipay = new PayTask(activity);
Map<String, String> result = alipay.payV2(orderStr, true);
传输过程中不要进行以下操作:
- 再次对整个
orderStr执行 URL 编码; - 手工替换
+、/、=、&、引号或空格; - 拆分
orderStr后重新排序或拼接; - 在客户端重新签名;
- 把经过 JSON 转义的字符串直接传给支付宝。
如果接口通过 JSON 返回订单串,需要确保客户端拿到的是反序列化后的原始字符串,而不是含有 \" 的 JSON 字面量。
4. 核对订单和签名配置
查询订单成功,只能说明部分网关请求可以正常执行。APP 支付使用的配置仍需单独核对:
app_id是否对应已经开通 APP 支付的应用;- 签名方式是否为当前配置对应的
RSA2; - 服务端使用的是否为应用私钥;
- SDK 中配置的是否为支付宝公钥,而不是应用公钥;
product_code是否为QUICK_MSECURITY_PAY;out_trade_no是否唯一;total_amount是否大于 0,并符合金额格式要求;- 服务器时间是否准确;
- 正式 APPID 不要调用沙箱网关,沙箱 APPID 也不要调用正式网关。
可以在服务端记录生成后的 orderStr,再与客户端调用支付前收到的字符串进行摘要比对,确认订单串在传输过程中没有变化:
String serverDigest = sha256(orderStr);
客户端也对收到的原始字符串计算相同摘要。如果结果不同,应优先排查接口序列化、字符编码和网络层处理。
5. 观察 6001 出现的具体时机
如果支付宝收银台能够正常打开,之后用户关闭页面或按下返回键,返回 6001 就是正常的取消流程,无需修改签名或订单参数。
如果收银台尚未出现便立即返回 6001,请重点检查:
Activity是否正在结束或切换;- 是否重复调用了支付方法;
- 调用期间是否发生页面跳转、登录失效或进程重建;
- 是否在非主流程、错误的上下文或不合适的生命周期阶段启动支付;
- 支付宝客户端能否正常启动;
- 手机系统是否拦截应用跳转;
orderStr是否为空、被截断或被转义。
也可以更换设备和网络进行交叉测试,排除支付宝客户端状态、系统拦截或网络环境的影响。
服务端必须再次确认交易结果
收到 6001 后,服务端订单通常仍应保持“待支付”或“已取消展示”状态。不要仅凭客户端结果关闭服务端订单,可以调用订单查询接口确认实际交易状态:
AlipayTradeQueryRequest queryRequest = new AlipayTradeQueryRequest();
AlipayTradeQueryModel queryModel = new AlipayTradeQueryModel();
queryModel.setOutTradeNo(outTradeNo);
queryRequest.setBizModel(queryModel);
AlipayTradeQueryResponse queryResponse =
alipayClient.execute(queryRequest);
if (queryResponse.isSuccess()) {
String tradeStatus = queryResponse.getTradeStatus();
// 仅根据明确的支付宝交易状态更新本地订单
}
同时,需要正确验签并处理 notify_url 收到的异步通知。即使客户端返回 9000,也不能代替服务端确认。
注意事项
- 不要把
6001当作签名失败,并因此重新生成密钥。 - 不要因为客户端返回
6001就立即创建新的商户订单号,原订单可能仍可继续支付。 - 日志可以记录订单号和返回状态,但不要完整输出商户私钥。
- 额度限制解除后,如果支付仍在收银台未显示时立即返回
6001,应将完整的客户端返回内容、APPID、商户订单号、发生时间和支付宝客户端版本提交给支付宝技术支持,以便进一步定位。
备注:内容仅供参考。
