PAYATHON 2026

PC统一收单下单并支付页面接口何时生成支付宝交易号

支付小周

明确结论

alipay.trade.page.pay(统一收单下单并支付页面接口)的调用结果不会直接返回支付宝交易号 trade_no。

该接口返回的是跳转到支付宝收银台所需的 HTML 表单。此时用户还没有完成付款,商户系统应使用自己的订单号 out_trade_no 跟踪订单。

买家完成支付后,可通过以下方式获取 trade_no:

  1. 接收支付宝发送到 notify_url 的异步通知,从通知参数中读取 trade_no。
  2. 调用 alipay.trade.query 主动查询交易。
  3. return_url 的同步跳转参数中也可能包含 trade_no,但不能据此确认支付结果。

为什么下单接口不直接返回 trade_no

alipay.trade.page.pay 用于生成支付页面,并不会在调用接口时同步完成付款。通常的处理流程如下:

商户创建订单
    ↓
调用 alipay.trade.page.pay
    ↓
获得并输出 HTML 表单
    ↓
用户进入支付宝收银台
    ↓
用户完成支付
    ↓
支付宝异步通知 notify_url
    ↓
商户验签、核对订单并保存 trade_no

调用页面支付接口时,商户能够确定的是自己生成的订单号 out_trade_no。支付宝交易号 trade_no 是支付宝侧的交易标识,商户不能自行生成或推算。

商户系统不需要依赖支付宝内部生成 trade_no 的具体时间点。处理业务时,以支付后的异步通知或交易查询结果中返回的 trade_no 为准。

推荐获取方式:处理异步通知

创建支付请求时,需要设置一个可从公网访问的 notify_url:

AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setNotifyUrl("https://www.example.com/alipay/notify");
request.setReturnUrl("https://www.example.com/alipay/return");

request.setBizContent("""
{
  "out_trade_no": "ORDER_202609090001",
  "total_amount": "99.00",
  "subject": "测试商品",
  "product_code": "FAST_INSTANT_TRADE_PAY"
}
""");

AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
String form = response.getBody();

这里的 form 是支付页面表单,不是包含 trade_no 的普通 JSON 数据。商户需要将表单输出到浏览器,再由浏览器提交表单并跳转至支付宝收银台。

支付完成后,异步通知通常包含以下参数:

out_trade_no=ORDER_202609090001
trade_no=20260909220014XXXXXXXXXX
trade_status=TRADE_SUCCESS
total_amount=99.00

服务端收到通知后,应先验签,然后读取并保存 trade_no:

Map<String, String> params = new HashMap<>();

request.getParameterMap().forEach((key, values) -> {
    if (values != null && values.length > 0) {
        params.put(key, String.join(",", values));
    }
});

boolean valid = AlipaySignature.rsaCheckV1(
    params,
    ALIPAY_PUBLIC_KEY,
    "UTF-8",
    "RSA2"
);

if (!valid) {
    response.getWriter().write("failure");
    return;
}

String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
String tradeStatus = params.get("trade_status");
String totalAmount = params.get("total_amount");

if ("TRADE_SUCCESS".equals(tradeStatus)
        || "TRADE_FINISHED".equals(tradeStatus)) {
    // 核对 app_id、out_trade_no、total_amount、seller_id 等关键字段。
    // 使用 out_trade_no 幂等更新订单,并保存 tradeNo。
}

response.getWriter().write("success");

实际开发时,需要根据所用支付宝 SDK 的版本调整类名和方法签名。

未收到通知时主动查询

如果异步通知出现延迟,或者商户服务暂时不可用,可使用商户订单号调用 alipay.trade.query:

AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("""
{
  "out_trade_no": "ORDER_202609090001"
}
""");

AlipayTradeQueryResponse queryResponse = alipayClient.execute(request);

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

    // 核对金额和商户身份后,幂等更新本地订单。
}

查询接口支持传入 out_trade_no。因此,即使本地还没有 trade_no,商户也可以查询支付宝侧的交易状态。支付成功后,查询结果会返回支付宝交易号。

如果交易尚未建立、订单号不存在,或者支付状态还没有更新,查询接口可能暂时无法返回有效的 trade_no。遇到这种情况,可根据业务需要进行有限次数的重试,避免高频轮询。

return_url 为什么不能作为支付依据

用户付款后,浏览器可能跳转到 return_url,同步参数中也可能包含 trade_no。但浏览器跳转并不可靠,常见情况包括:

  • 用户付款后直接关闭页面。
  • 网络中断,跳转没有完成。
  • 浏览器重复刷新或重复访问。
  • 请求参数可能被伪造,因此必须验证签名。

return_url 适合展示“支付处理中”或支付结果页面,也可以用来触发一次订单查询,但不适合直接将订单修改为已支付。各接口的用途如下:

return_url:改善用户体验,展示结果或触发一次订单查询
notify_url:服务端确认支付并更新订单
alipay.trade.query:通知缺失时进行主动补偿

注意事项

  • out_trade_no 是商户生成的订单号,trade_no 是支付宝生成的交易号,两者不能混用。
  • 收到异步通知后,必须验证签名,并核对 app_id、seller_id、订单号、金额和交易状态。
  • 支付宝可能重复发送异步通知,因此订单更新必须以 out_trade_no 为依据,并做好幂等处理。
  • 不要只凭前端提示、同步跳转或客户端提交的 trade_no 判断支付成功。
  • 本地订单表中建议同时保存 out_trade_no 和 trade_no,便于后续处理退款、撤销、对账和交易查询。
  • 向支付宝返回 success 前,应确认关键业务处理已经成功。如果处理失败,不要返回虚假的成功结果。

备注:内容仅供参考。