支付宝小程序未支付订单的交易号能否重复使用及有效期
结论
可以,前提是上一次创建的支付宝订单仍可支付。
先分清两个编号:
out_trade_no:商户系统生成的商户订单号。trade_no:支付宝交易号,通常在调用alipay.trade.create创建订单后返回。
用户取消支付页面,不代表交易已经关闭。后端查询并确认订单状态仍为 WAIT_BUYER_PAY 后,可以把原来的 trade_no 返回给小程序前端,再通过 my.tradePay 拉起支付。
不要因为前端返回“取消支付”就创建新订单,也不要跳过状态查询直接复用交易号。
为什么可以重新拉起
取消收银台通常只表示用户中断了这次支付操作,支付宝侧的交易可能仍然存在。只要交易尚未支付成功、关闭或超时,原支付宝交易号就可以继续用于支付。
同一笔业务订单应尽量使用同一个 out_trade_no,以免:
- 重复创建支付宝交易;
- 用户重复付款;
- 支付回调难以对应业务订单;
- 对账时出现一笔业务订单对应多笔支付宝交易的情况。
out_trade_no 并不是小程序拉起支付时使用的支付宝交易号。调用 my.tradePay 时,一般要传入创建订单接口返回的 trade_no:
my.tradePay({
tradeNO: tradeNo,
success: (res) => {
console.log('支付操作完成', res);
},
fail: (err) => {
console.error('支付调用失败', err);
}
});
推荐处理流程
用户再次点击“支付”时,后端先根据 out_trade_no 查询支付宝交易状态,例如调用 alipay.trade.query,然后根据查询结果处理。
交易仍待支付
状态为 WAIT_BUYER_PAY 时,可以返回此前保存的 trade_no:
{
"out_trade_no": "ORDER_202609080001",
"trade_no": "2026090822000000000000000000",
"action": "PAY_EXISTING"
}
前端再使用这个 trade_no 拉起支付。
交易已经成功
状态为 TRADE_SUCCESS 或 TRADE_FINISHED 时,不要再次拉起支付。后端应根据支付宝查询结果或异步通知更新本地订单状态,并向前端返回“已支付”。
交易已经关闭
状态为 TRADE_CLOSED 时,原 trade_no 已无法继续支付。此时应按照业务规则生成新的商户订单号,并创建新的支付宝交易。
交易关闭后,不建议继续使用原 out_trade_no 创建新交易。更稳妥的处理方式是生成新的支付流水号,同时将其关联到原业务订单。
查询不到交易
如果支付宝返回交易不存在,需要检查:
- 第一次创建订单是否成功;
out_trade_no是否属于当前支付宝应用和商户;- 应用环境是否一致,例如正式环境和沙箱环境是否混用;
- 本地是否正确保存了创建接口返回的
trade_no。
确认交易确实不存在后,再决定是否重新创建。
后端示例
下面的示例只展示核心判断逻辑。具体 SDK 方法名应以项目实际使用的支付宝 SDK 为准:
public PayResult retryPay(String outTradeNo) {
LocalOrder order = orderRepository.findByOutTradeNo(outTradeNo);
if (order == null) {
throw new IllegalArgumentException("商户订单不存在");
}
AlipayTradeQueryResponse response =
alipayClient.execute(buildQueryRequest(outTradeNo));
if (!response.isSuccess()) {
throw new IllegalStateException(
"支付宝订单查询失败:" + response.getSubMsg()
);
}
String tradeStatus = response.getTradeStatus();
switch (tradeStatus) {
case "WAIT_BUYER_PAY":
String tradeNo = response.getTradeNo();
orderRepository.saveTradeNo(outTradeNo, tradeNo);
return PayResult.payExisting(outTradeNo, tradeNo);
case "TRADE_SUCCESS":
case "TRADE_FINISHED":
orderService.markPaid(outTradeNo, response.getTradeNo());
return PayResult.alreadyPaid(outTradeNo);
case "TRADE_CLOSED":
return createNewPaymentFor(order);
default:
throw new IllegalStateException(
"暂不支持的交易状态:" + tradeStatus
);
}
}
订单创建成功后,应立即保存支付宝返回的 trade_no,不要完全依赖后续查询获取:
AlipayTradeCreateResponse response =
alipayClient.execute(createRequest);
if (!response.isSuccess()) {
throw new IllegalStateException(
"创建支付宝订单失败:" + response.getSubMsg()
);
}
orderRepository.savePaymentInfo(
outTradeNo,
response.getTradeNo()
);
有效期如何确定
不要脱离订单配置,单独为 trade_no 设置一个固定有效期。它能否再次用于支付,取决于支付宝交易是否仍处于 WAIT_BUYER_PAY 状态。
如果创建交易时设置了 timeout_express,订单通常会按照该配置在超时后进入不可支付状态。例如:
{
"out_trade_no": "ORDER_202609080001",
"total_amount": "99.00",
"subject": "商品订单",
"timeout_express": "30m"
}
这里的 30m 表示订单支付超时时间为 30 分钟。支持的格式、取值范围、默认期限和实际关单时间,应以当前接入接口的官方文档及支付宝查询结果为准。即使按照本地时间计算尚未超时,最终仍应以 alipay.trade.query 返回的交易状态为准。
注意事项
- 不要把“用户取消支付”直接视为订单关闭。
- 不要仅根据前端回调认定支付成功。支付结果应以后端查询和支付宝异步通知为准。
- 同一个
out_trade_no应对应同一笔业务交易,金额、商品信息等内容不应随意更改。 - 重新支付前必须校验订单所属用户,避免他人仅凭
out_trade_no获取或支付不属于自己的订单。 - “查询订单”和“创建订单”可能并发执行。后端应使用数据库唯一索引、状态锁或幂等机制,防止重复创建。
- 如果需要重新计时、修改金额或更换商品,应先确认旧交易已经关闭,再使用新的
out_trade_no创建交易。 - 前端字段通常写作
tradeNO,支付宝接口返回字段通常写作trade_no。注意两者的大小写和命名方式,不要混用。
备注:内容仅供参考。
