调用alipay.trade.page.pay后关闭订单提示交易不存在
结论
调用 SDK 的 alipay.trade.page.pay,通常只会生成一段用于跳转至支付宝收银台的 HTML 表单。生成表单并不等于支付宝已经创建交易。
交易需要经过以下过程才会进入支付宝系统:用户浏览器提交表单,支付宝网关接收支付请求,然后创建交易。因此,如果生成表单后马上调用 alipay.trade.close 或 alipay.trade.query,支付宝可能还查不到这笔交易,并提示“交易不存在”。
原因说明
以 Java SDK 为例:
String form = alipayClient.pageExecute(request).getBody();
这段代码返回的是 HTML 表单,完整流程如下:
商户生成支付表单
↓
浏览器提交表单并跳转支付宝收银台
↓
支付宝接收支付请求并创建交易
↓
交易才可以被查询或关闭
如果只执行 pageExecute,没有将返回的表单输出到浏览器并完成提交,支付宝系统中就还没有这笔交易。
直接进入支付页面时之所以可以正常付款,是因为浏览器在跳转收银台的过程中提交了支付请求,支付宝收到请求后才会创建交易。
正确处理方式
1. 将支付表单返回给浏览器
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setReturnUrl(returnUrl);
request.setNotifyUrl(notifyUrl);
AlipayTradePagePayModel model = new AlipayTradePagePayModel();
model.setOutTradeNo(outTradeNo);
model.setTotalAmount("100.00");
model.setSubject("测试订单");
model.setProductCode("FAST_INSTANT_TRADE_PAY");
request.setBizModel(model);
String form = alipayClient.pageExecute(request).getBody();
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(form);
response.getWriter().flush();
浏览器收到表单后会自动提交,并跳转到支付宝收银台。支付宝收到这次请求后,才会创建对应的交易。
因此,生成表单成功不能直接视为支付宝订单创建成功。
2. 确认交易进入支付宝系统后再查询
可以通过商户订单号 out_trade_no 查询:
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
model.setOutTradeNo(outTradeNo);
request.setBizModel(model);
AlipayTradeQueryResponse queryResponse = alipayClient.execute(request);
if (queryResponse.isSuccess()) {
System.out.println("tradeStatus: " + queryResponse.getTradeStatus());
System.out.println("tradeNo: " + queryResponse.getTradeNo());
} else {
System.out.println("code: " + queryResponse.getCode());
System.out.println("subCode: " + queryResponse.getSubCode());
System.out.println("subMsg: " + queryResponse.getSubMsg());
}
收银台刚打开时,交易数据可能不会立即变得可查。业务逻辑需要允许短暂延迟,并设置有限次数、带时间间隔的重试,避免高频轮询。
3. 只关闭已经创建且可以关闭的交易
确认交易存在后,可以使用相同的 out_trade_no,也可以使用查询得到的支付宝交易号 trade_no 发起关闭:
AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
AlipayTradeCloseModel model = new AlipayTradeCloseModel();
model.setOutTradeNo(outTradeNo);
request.setBizModel(model);
AlipayTradeCloseResponse closeResponse = alipayClient.execute(request);
if (closeResponse.isSuccess()) {
System.out.println("订单关闭成功");
} else {
System.out.println("code: " + closeResponse.getCode());
System.out.println("subCode: " + closeResponse.getSubCode());
System.out.println("subMsg: " + closeResponse.getSubMsg());
}
如果用户从未提交支付表单,支付宝系统中原本就没有这笔交易,也就不需要调用 alipay.trade.close。这种情况下,只需在商户自己的订单系统中取消或关闭订单。
建议的订单状态设计
商户系统需要区分“已生成支付请求”和“支付宝交易已创建”。例如:
CREATED 商户订单已创建
PAY_FORM_GENERATED 已生成支付表单,但不代表支付宝交易存在
PAYING 用户已进入支付流程
PAID 已收到可靠的支付成功结果
CLOSED 商户订单或支付宝交易已关闭
支付表单生成后,不应立即把订单标记为“支付宝交易已创建”。支付状态应根据异步通知和主动查询结果进行确认。
注意事项
- 查询或关闭交易时使用的
out_trade_no,必须与alipay.trade.page.pay提交的值完全一致。 - 三个接口必须使用同一个
app_id、同一套应用配置和同一环境,不能混用沙箱环境与生产环境。 return_url只是用户页面的跳转地址,不能单独作为支付成功的最终依据。- 支付结果应优先通过支付宝异步通知处理,必要时再调用
alipay.trade.query核验。 - 返回支付表单后不要马上执行关闭逻辑,否则可能发生交易尚未创建,或用户刚进入收银台,交易就被关闭的竞态问题。
- 如果已经确认浏览器成功提交表单,但仍然持续查不到交易,需要检查网关返回页面、签名、参数、应用环境,以及完整的
code、sub_code和sub_msg,不能只根据“交易不存在”这段提示判断原因。
备注:内容仅供参考。
