alipay.trade.precreate 创建二维码后沙箱支付宝付款失败
结论
alipay.trade.precreate 返回二维码,只能说明交易预创建成功,不能保证后续付款一定可用。扫描沙箱二维码后,支付宝一直提示繁忙,通常不是二维码图片生成失败,而是沙箱环境、买家账号或请求配置不一致。
可以先检查这些项目:
- 请求是否发往支付宝沙箱网关;
app_id、应用私钥和支付宝公钥是否来自同一个沙箱应用;- 沙箱支付宝是否登录了沙箱买家账号;
- 二维码是否来自本次成功的预创建响应,且仍在有效期内;
out_trade_no是否重复;- 预创建接口是否确实返回
code=10000; - 沙箱服务是否暂时异常。
如果所有配置都正确,但更换订单后仍然出现相同提示,支付宝沙箱的付款链路可能暂时不可用。沙箱的稳定性与生产环境并不完全相同。建议保留接口响应和订单号,稍后再测试。
确认预创建接口是否成功
不要只看程序有没有生成二维码图片,还要检查支付宝返回的业务状态:
{
"alipay_trade_precreate_response": {
"code": "10000",
"msg": "Success",
"out_trade_no": "TEST_202609090001",
"qr_code": "https://qr.alipay.com/..."
},
"sign": "..."
}
满足下面两个条件,才表示预创建成功:
code == "10000"
qr_code 非空
如果响应中包含 sub_code 和 sub_msg,排查时应优先查看这两个字段。签名、权限、参数或商户状态等问题,通常会在这里给出更具体的信息。
核对沙箱环境配置
调用沙箱接口时,必须使用以下网关:
https://openapi-sandbox.dl.alipaydev.com/gateway.do
这些配置必须来自同一个沙箱应用:
app_id
应用私钥
支付宝公钥
sign_type
常见情况是使用了沙箱 app_id,却配置了生产环境的支付宝公钥,或者代码仍在请求生产网关。有些配置错误会直接导致预创建失败,有些则会等到扫码付款时才暴露出来。
Java SDK 配置示例:
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi-sandbox.dl.alipaydev.com/gateway.do",
sandboxAppId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
其中,alipayPublicKey 必须是该沙箱应用对应的支付宝公钥,不能使用应用公钥或生产环境公钥。
使用正确的沙箱买家账号
测试沙箱二维码时,应使用沙箱支付宝客户端,并登录沙箱提供的买家账号。以下组合都不正确:
- 用普通支付宝客户端扫描沙箱二维码;
- 在沙箱支付宝中登录真实支付宝账号;
- 用沙箱商户账号代替沙箱买家账号付款;
- 由一个沙箱应用创建订单,再用另一个沙箱环境的账号或配置付款。
同时要确认沙箱买家账号状态正常,并有足够的测试余额。如果无法确定账号状态,可以前往支付宝开放平台的沙箱账号页面重新核对买家账号信息。
每次测试使用新的商户订单号
out_trade_no 是商户订单号,在商户范围内必须唯一。如果重复使用已经支付、关闭或状态异常的订单号,后续测试结果可能不符合预期。
测试订单号可以按时间和随机值生成:
String outTradeNo =
"SANDBOX_" +
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) +
"_" +
UUID.randomUUID().toString().replace("-", "").substring(0, 8);
预创建请求示例:
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
request.setNotifyUrl("https://example.com/alipay/notify");
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", outTradeNo);
bizContent.put("total_amount", "0.01");
bizContent.put("subject", "沙箱扫码支付测试");
request.setBizContent(bizContent.toJSONString());
AlipayTradePrecreateResponse response = alipayClient.execute(request);
if (response.isSuccess()
&& "10000".equals(response.getCode())
&& response.getQrCode() != null) {
System.out.println("out_trade_no: " + response.getOutTradeNo());
System.out.println("qr_code: " + response.getQrCode());
} else {
System.out.println("code: " + response.getCode());
System.out.println("msg: " + response.getMsg());
System.out.println("sub_code: " + response.getSubCode());
System.out.println("sub_msg: " + response.getSubMsg());
System.out.println("body: " + response.getBody());
}
不要自行拼接或修改 qr_code。应直接把响应中的完整字符串编码成二维码,并确认生成过程中没有截断、转义或替换字符。
查询订单的实际状态
客户端提示繁忙,不能直接证明订单没有创建或付款失败。可以调用 alipay.trade.query 查询交易状态:
AlipayTradeQueryRequest queryRequest = new AlipayTradeQueryRequest();
JSONObject queryContent = new JSONObject();
queryContent.put("out_trade_no", outTradeNo);
queryRequest.setBizContent(queryContent.toJSONString());
AlipayTradeQueryResponse queryResponse = alipayClient.execute(queryRequest);
System.out.println("code: " + queryResponse.getCode());
System.out.println("sub_code: " + queryResponse.getSubCode());
System.out.println("sub_msg: " + queryResponse.getSubMsg());
System.out.println("trade_status: " + queryResponse.getTradeStatus());
System.out.println("body: " + queryResponse.getBody());
常见交易状态包括:
WAIT_BUYER_PAY
TRADE_SUCCESS
TRADE_CLOSED
TRADE_FINISHED
查询结果为 WAIT_BUYER_PAY,表示预创建订单仍然存在,但扫码付款尚未完成。如果响应返回了明确的 sub_code,可以根据错误码继续排查。如果查询不到交易,应重新核对网关、app_id 和 out_trade_no 是否一致。
排查顺序
- 记录
alipay.trade.precreate的完整响应,确认code=10000。 - 确认请求使用的是沙箱网关。
- 核对
app_id、应用私钥、支付宝公钥和RSA2配置。 - 更换
out_trade_no,重新创建订单。 - 直接使用响应中的
qr_code生成二维码。 - 在沙箱支付宝中登录沙箱买家账号后扫码。
- 调用
alipay.trade.query查询订单状态。 - 间隔一段时间再次测试,排除沙箱服务临时异常。
注意事项
沙箱支付宝的客户端功能和稳定性可能与正式支付宝不同。繁忙是客户端的通用提示,仅凭这条提示无法确定具体原因。判断时需要结合预创建响应和交易查询响应,重点查看其中的 code、sub_code 和 sub_msg。
异步通知地址无法访问,一般不会阻止买家完成付款,但商户端将收不到支付通知。测试时仍应确保 notify_url 可以从公网访问,并且只在通知验签成功后更新订单状态。
切换到生产环境前,还要换成生产网关和生产应用配置,不能继续使用沙箱账号、密钥或二维码。
备注:内容仅供参考。
