支付宝沙箱 app支付首次成功后一直提示系统繁忙
结论
这种情况通常不是金额“18 元”触发了限制。先检查第二次支付是否重复使用了第一次的商户订单号 out_trade_no。
在同一商户应用下,out_trade_no 必须唯一。第一次支付成功后,如果再次使用相同订单号创建支付,支付宝会将其识别为已有交易,并可能返回订单重复、交易状态不允许继续支付等错误。部分客户端只会显示统一的“系统繁忙”,所以不能仅凭页面提示判断原因。
如果每次使用的订单号都不同,再依次检查服务端返回的 sub_code、沙箱账号状态、签名配置、网关环境和订单参数。
检查 out_trade_no
不要在代码中写死订单号,也不要只用秒级时间戳生成订单号。建议由服务端生成全局唯一的订单号,并保存订单号与业务订单之间的对应关系。
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
public class OrderNoGenerator {
public static String generate() {
String time = LocalDateTime.now()
.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
String random = UUID.randomUUID()
.toString()
.replace("-", "")
.substring(0, 12);
return time + random;
}
}
创建 APP 支付订单时,每笔新交易都要使用新的订单号:
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setOutTradeNo(OrderNoGenerator.generate());
model.setTotalAmount("18.00");
model.setSubject("测试商品");
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl("https://example.com/alipay/notify");
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
if (!response.isSuccess()) {
System.out.println("code: " + response.getCode());
System.out.println("msg: " + response.getMsg());
System.out.println("subCode: " + response.getSubCode());
System.out.println("subMsg: " + response.getSubMsg());
throw new IllegalStateException("支付宝下单失败");
}
String orderString = response.getBody();
客户端应直接使用服务端返回的完整 orderString 调起支付宝 SDK,不要自行拼接或修改参数。
订单号必须唯一,但这不代表支付失败后一定要立即更换订单号。如果业务上需要继续支付同一笔未完成的订单,应先查询原交易状态,再决定继续支付、关闭原订单,还是创建新订单。不能不做判断就重复下单。
获取实际错误信息
“系统繁忙”通常只是客户端给出的概括性提示。排查时至少要记录以下两部分信息:
- 服务端调用支付宝接口后返回的
code、msg、sub_code、sub_msg - APP 支付 SDK 返回的
resultStatus、memo和result
Android 端示例:
PayTask payTask = new PayTask(activity);
Map<String, String> result = payTask.payV2(orderString, true);
String resultStatus = result.get("resultStatus");
String memo = result.get("memo");
String resultData = result.get("result");
Log.i("Alipay", "resultStatus=" + resultStatus);
Log.i("Alipay", "memo=" + memo);
Log.i("Alipay", "result=" + resultData);
不要只记录页面上的中文提示。支付宝接口返回的错误码和子错误码更有定位价值。不同错误码对应的处理方式不同,应根据实际返回结果查阅官方错误码说明。
还要检查后端是否把支付宝下单失败错误地包装成了正常响应。例如,当 response.isSuccess() 为 false 时,后端仍将 response.getBody() 返回给客户端。客户端拿到无效订单串后,最终可能只显示“系统繁忙”。
查询第一次交易的状态
如果怀疑订单号被重复使用,可以通过交易查询接口确认第一次订单的当前状态:
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
model.setOutTradeNo("第一次支付使用的商户订单号");
request.setBizModel(model);
AlipayTradeQueryResponse response = alipayClient.execute(request);
System.out.println("code: " + response.getCode());
System.out.println("msg: " + response.getMsg());
System.out.println("subCode: " + response.getSubCode());
System.out.println("subMsg: " + response.getSubMsg());
System.out.println("tradeStatus: " + response.getTradeStatus());
System.out.println("tradeNo: " + response.getTradeNo());
如果查询结果显示原订单已经支付成功,就不能再将其当作新订单使用。新一轮付款需要创建新的业务订单,并分配新的 out_trade_no。
如果订单状态未知,不要只根据客户端返回结果修改本地订单状态。应结合交易查询结果和支付宝异步通知进行确认。
检查沙箱环境是否混用
如果订单号没有重复,继续核对以下配置是否都属于同一个沙箱应用:
- 支付宝网关使用沙箱地址
app_id是当前沙箱应用的 App ID- 应用私钥与上传至该沙箱应用的公钥相匹配
- 支付宝公钥没有误填为应用公钥
- 签名算法配置一致,通常为
RSA2 - APP 使用沙箱测试账号,而不是正式支付宝账号
- 服务端和客户端没有混用正式环境与沙箱环境生成的参数
Java SDK 初始化示例:
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi-sandbox.dl.alipaydev.com/gateway.do",
appId,
appPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
支付宝开放平台可能调整沙箱网关和配置方式,具体信息应以当前控制台及官方文档为准。
检查沙箱买家账号
还需要确认以下事项:
- 使用的是沙箱提供的买家账号
- 账号余额充足
- 没有在正式支付宝客户端与沙箱客户端之间混用账号
- 沙箱账号、应用配置或密钥近期没有被重置
- 更换沙箱买家账号后,问题是否仍然存在
如果只有某个买家账号无法付款,而其他沙箱买家账号可以正常支付,问题更可能出在该测试账号的余额或状态上。如果所有账号都支付失败,应重点检查商户订单号、签名、接口响应和沙箱环境配置。
建议的排查顺序
- 打印连续两次请求的
out_trade_no,确认两者是否完全相同。 - 检查服务端下单响应,记录
code、sub_code和sub_msg。 - 查询第一次支付对应的交易状态。
- 确认客户端拿到的是本次请求新生成的
orderString,而不是缓存中的旧订单串。 - 核对沙箱网关、App ID、密钥、支付宝公钥和签名算法。
- 检查沙箱买家账号及余额,并尝试更换测试账号。
- 如果参数正确但仍然支付失败,保留请求时间、
out_trade_no、支付宝交易号和完整错误码,再通过支付宝开放平台的支持渠道排查。
注意事项
最终支付结果应以支付宝异步通知或主动查询结果为准。客户端显示“支付成功”只能作为交互提示,不能直接作为最终入账依据。
异步通知验签成功后,还要核对:
app_idout_trade_nototal_amountseller_id- 交易状态
金额应使用十进制字符串,例如 "18.00",不要使用 double 计算金额。金额格式通常不会导致“第一次成功,之后一直失败”,但规范处理可以避免精度和参数校验问题。
根据这一现象,应该先确认 out_trade_no 是否被写死、缓存或重复提交。为每笔新支付生成独立订单号,再结合实际错误码继续排查,通常可以找到问题所在。
备注:内容仅供参考。
