PAYATHON 2026

alipay.trade.close 提示交易不存在,如何关闭订单?

支付阿杰

结论

alipay.trade.wap.pay 返回支付表单或支付链接时,支付宝侧不一定已经创建交易。用户实际打开支付宝收银台并提交支付请求后,支付宝才可能生成对应交易。

如果用户尚未进入收银台就调用 alipay.trade.close,支付宝无法查询到 out_trade_no 对应的交易,返回“交易不存在”属于正常情况。此时关闭商户系统中的订单即可,无须反复调用支付宝关单接口。

交易已经支付成功时,应调用退款接口,而不是关单接口。alipay.trade.close 主要用于关闭待支付交易。

为什么会出现“交易不存在”

手机网站支付通常分为两个阶段:

  1. 商户系统创建本地订单,生成 alipay.trade.wap.pay 请求表单或跳转地址。
  2. 用户提交表单并进入支付宝收银台,支付宝受理请求并创建交易。

如果流程只完成了第一步,支付宝侧可能还没有这笔交易。此时调用:

alipay.trade.close

即使传入的 out_trade_no 与本地订单号完全一致,也可能收到“交易不存在”的响应。

“商户订单已创建”和“支付宝交易已创建”是两个不同的状态。商户系统需要维护自己的订单生命周期,不能根据支付宝交易是否存在来决定能否关闭本地订单。

正确的处理流程

1. 先关闭商户本地订单

订单超过支付期限或用户主动取消时,应先将本地订单更新为“已关闭”或“已取消”,同时禁止该订单继续触发业务交付。

更新订单时需要附带状态条件,避免支付通知与关单任务并发执行,错误覆盖订单状态。例如,只允许把“待支付”订单改为“已关闭”:

UPDATE payment_order
SET status = 'CLOSED',
    closed_at = CURRENT_TIMESTAMP
WHERE out_trade_no = ?
  AND status = 'WAIT_PAY';

随后根据受影响行数判断更新是否成功。如果受影响行数为 0,需要重新读取订单,确认其是否已经支付、关闭或退款。

2. 查询支付宝交易状态

如果用户可能进入过支付宝收银台,可以先调用:

alipay.trade.query

再根据查询结果分别处理:

  • 返回交易不存在:支付宝侧没有可关闭的交易,只需关闭本地订单。
  • WAIT_BUYER_PAY:调用 alipay.trade.close。
  • TRADE_CLOSED:无须再次关单。
  • TRADE_SUCCESS 或 TRADE_FINISHED:不能再按未支付订单处理。如需退回资金,应根据业务规则调用退款接口。
  • 查询失败或网络超时:不能直接认定交易不存在,应记录任务并重试,或交由人工核对。

3. 只关闭待支付交易

以下是使用 Java SDK 的示意代码。具体类名和字段应以项目实际使用的支付宝 SDK 版本为准。

AlipayTradeQueryRequest queryRequest = new AlipayTradeQueryRequest();
queryRequest.setBizContent(
    "{\"out_trade_no\":\"" + outTradeNo + "\"}"
);

AlipayTradeQueryResponse queryResponse = alipayClient.execute(queryRequest);

if (queryResponse.isSuccess()) {
    String tradeStatus = queryResponse.getTradeStatus();

    if ("WAIT_BUYER_PAY".equals(tradeStatus)) {
        AlipayTradeCloseRequest closeRequest = new AlipayTradeCloseRequest();
        closeRequest.setBizContent(
            "{\"out_trade_no\":\"" + outTradeNo + "\"}"
        );

        AlipayTradeCloseResponse closeResponse =
            alipayClient.execute(closeRequest);

        if (!closeResponse.isSuccess()) {
            // 记录 code、sub_code、msg 和 sub_msg,后续重试或人工处理
            throw new IllegalStateException(
                "支付宝关单失败:" + closeResponse.getSubCode()
                + " - " + closeResponse.getSubMsg()
            );
        }
    } else if ("TRADE_SUCCESS".equals(tradeStatus)
            || "TRADE_FINISHED".equals(tradeStatus)) {
        // 交易已经付款,不应调用关单接口。
        // 如业务需要退回资金,应进入退款流程。
    } else if ("TRADE_CLOSED".equals(tradeStatus)) {
        // 已关闭,无须再次处理
    }
} else if (isTradeNotExist(queryResponse)) {
    // 支付宝侧尚未创建交易,本地保持关闭状态即可
} else {
    // 系统异常、签名问题、权限问题或网络问题不能按“交易不存在”处理
    // 记录完整错误信息并安排重试
}

判断是否属于“交易不存在”时,应检查响应中的 code、sub_code 等结构化字段,不要只匹配中文错误文案:

private boolean isTradeNotExist(AlipayTradeQueryResponse response) {
    String subCode = response.getSubCode();

    // 具体错误码应以实际接口响应和当前支付宝接口文档为准。
    return "ACQ.TRADE_NOT_EXIST".equals(subCode);
}

设置支付有效期

调用 alipay.trade.wap.pay 时,可以根据接口支持情况设置 timeout_express,限制用户完成支付的时间。例如:

AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setReturnUrl(returnUrl);
request.setNotifyUrl(notifyUrl);

request.setBizContent("""
{
  "out_trade_no": "ORDER_202609090001",
  "total_amount": "99.00",
  "subject": "订单支付",
  "product_code": "QUICK_WAP_WAY",
  "timeout_express": "15m"
}
""");

timeout_express 限制的是支付有效时间。商户仍需通过本地定时任务管理订单超时,不能认为有效期结束后,支付宝状态会立即同步到商户系统。

必须处理支付与关单并发

关单任务执行期间,用户可能正好完成支付。即使本地订单已经标记为关闭,也不能忽略支付宝异步通知。

收到支付通知后,需要:

  1. 验证签名。
  2. 校验 app_id、商户身份、out_trade_no、金额和币种等字段。
  3. 使用原子更新或状态机处理订单。
  4. 如果本地订单已关闭,但支付宝确认付款成功,应进入异常支付处理流程,例如自动退款或人工审核。
  5. 按支付宝接口要求正确响应通知,避免重复通知引发额外处理。

注意事项

  • 生成支付表单不代表支付宝交易已经存在。
  • “交易不存在”也不意味着应无限重试接口。如果用户从未进入收银台,重复关单没有意义。
  • out_trade_no 必须与发起支付时完全一致,且交易应属于同一应用和商户主体。
  • 不要根据同步跳转结果判断最终支付状态。应以验签后的异步通知为主,必要时主动查询。
  • 支付成功的交易通常应调用 alipay.trade.refund,而不是 alipay.trade.close。
  • 查询超时、系统错误和验签错误需要分别处理,不能一律视为“交易不存在”。
  • 具体错误码、可关闭状态和参数能力可能随接口规范变化,应以当前接入环境的实际响应和支付宝开放平台文档为准。

备注:内容仅供参考。