PAYATHON 2026

支付宝查询使用out_trade_no提示交易不存在的原因

支付阿杰

结论

out_trade_no 和 trade_no 是两种不同的订单号,不能用同一个值替换查询。

  • out_trade_no:由商户系统生成,必须与创建或支付交易时提交给支付宝的商户订单号完全一致。
  • trade_no:由支付宝为交易生成,是支付宝交易号。

如果某个值填入 trade_no 可以查询成功,填入 out_trade_no 却提示交易不存在,通常表示它是支付宝交易号,不是创建交易时提交的商户订单号。

两个字段的区别

字段生成方含义查询条件
out_trade_no商户系统商户订单号必须匹配原交易中的商户订单号,并处于正确的应用、商户和环境上下文中
trade_no支付宝支付宝交易号必须是支付宝返回的真实交易号,并且当前调用方具有查询该交易的权限

创建交易时,商户一般会提交自己的 out_trade_no:

{
  "out_trade_no": "ORDER_20220328_001",
  "total_amount": "10.00",
  "subject": "测试订单"
}

支付宝受理交易后,会在同步响应或异步通知中返回 trade_no:

{
  "out_trade_no": "ORDER_20220328_001",
  "trade_no": "2022032822001400000000000000"
}

查询时要使用与字段对应的值。按商户订单号查询:

{
  "out_trade_no": "ORDER_20220328_001"
}

按支付宝交易号查询:

{
  "trade_no": "2022032822001400000000000000"
}

即使两者都是数字字符串,也不能把支付宝返回的 trade_no 当作 out_trade_no 传入。

为什么使用 out_trade_no 会提示交易不存在

常见原因如下。

1. 传入的其实是 trade_no

这与当前现象最为吻合。同一个值作为 trade_no 可以查询成功时,应先确认它的来源:

  • 如果来自支付宝支付响应的 trade_no 字段,就应使用 trade_no 查询。
  • 如果来自商户数据库中的订单编号,就应使用 out_trade_no 查询。
  • 不要通过号码的长度或格式判断字段类型,应以响应字段名和数据来源为准。

2. 商户订单号与支付时提交的不一致

out_trade_no 必须与创建交易时提交的字符串完全一致。以下情况都可能导致查询失败:

  • 查询时使用了业务订单号,而支付时提交的是支付流水号;
  • 订单号的前缀或后缀不同;
  • 补单或重试时重新生成了订单号;
  • 数据库存储时截断了订单号;
  • 字符串中有空格或大小写差异;
  • 传入了退款单号、预授权单号等其他业务编号。

应直接查看支付请求日志或支付宝异步通知中的 out_trade_no,不要根据业务数据推测。

3. 查询所用的应用或商户上下文不一致

使用 out_trade_no 查询时,除了订单号必须匹配,交易上下文也必须正确。需要核对:

  • 查询使用的 app_id 是否与创建交易时一致;
  • 签约商户或收款账号是否一致;
  • 服务商代商户调用时,app_auth_token 是否属于创建该交易的授权商户;
  • 是否在不同商户账号下使用了相同的商户订单号。

out_trade_no 是商户侧编号,不是支付宝平台的全局交易标识,无法只凭这个号码跨商户或跨应用查询交易。

4. 沙箱与生产环境混用

示例代码使用的是沙箱网关:

https://openapi.alipaydev.com/gateway.do

如果交易在生产环境创建,却通过沙箱网关查询,或者交易在沙箱环境创建,却通过生产网关查询,都会提示交易不存在。生产环境通常使用:

https://openapi.alipay.com/gateway.do

app_id、应用私钥、支付宝公钥和交易环境也必须配套,不能混用沙箱配置和生产配置。

5. 交易尚未在支付宝侧成功创建

商户系统可能已经生成了 out_trade_no,但创建交易的请求失败、没有成功发送,或者没有被支付宝受理。此时本地数据库虽然有订单,支付宝侧却可能没有对应的交易。

遇到这种情况,应检查原始的交易创建响应,而不只是确认本地订单是否存在。

推荐的查询写法

建议明确区分两种查询方法,不要使用含义模糊的 num 参数。

按商户订单号查询:

public AlipayTradeQueryResponse queryByOutTradeNo(
        AlipayClient alipayClient,
        String outTradeNo) throws AlipayApiException {

    AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();

    JSONObject bizContent = new JSONObject();
    bizContent.put("out_trade_no", outTradeNo);
    request.setBizContent(bizContent.toString());

    return alipayClient.execute(request);
}

按支付宝交易号查询:

public AlipayTradeQueryResponse queryByTradeNo(
        AlipayClient alipayClient,
        String tradeNo) throws AlipayApiException {

    AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();

    JSONObject bizContent = new JSONObject();
    bizContent.put("trade_no", tradeNo);
    request.setBizContent(bizContent.toString());

    return alipayClient.execute(request);
}

调用后还要检查错误码和子错误码:

AlipayTradeQueryResponse response =
        queryByOutTradeNo(alipayClient, "ORDER_20220328_001");

if (response.isSuccess()) {
    System.out.println("查询成功");
    System.out.println("out_trade_no: " + response.getOutTradeNo());
    System.out.println("trade_no: " + response.getTradeNo());
    System.out.println("trade_status: " + response.getTradeStatus());
} else {
    System.out.println("查询失败");
    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());
}

如果由服务商代商户查询,还需要使用创建交易时对应的应用授权令牌。具体传递方式取决于所用的支付宝 Java SDK 版本:

AlipayTradeQueryResponse response =
        alipayClient.execute(request, null, appAuthToken);

排查步骤

  1. 在支付创建请求中找到原始的 out_trade_no。
  2. 在支付响应或异步通知中找到支付宝返回的 trade_no。
  3. 使用各自对应的字段查询,不要重复使用来源不明的同一个号码。
  4. 核对查询和支付使用的 app_id、商户身份以及 app_auth_token。
  5. 确认查询与支付使用的是同一环境,不要混用沙箱网关和生产网关。
  6. 输出 code、sub_code、msg、sub_msg 和完整响应体,确认具体的失败原因。
  7. 如果本地有订单但支付宝查询不到,检查原始交易创建请求是否真正成功。

注意事项

同时传入 trade_no 和 out_trade_no,可能掩盖商户订单号错误,也会增加排查难度。实际开发时应选择一种含义明确的查询依据。

示例代码中还包含了疑似完整的应用私钥。不要把私钥写入源码、日志或公开内容。如果该密钥曾被实际使用或已经泄露,应立即在支付宝开放平台更换应用密钥,并通过环境变量、密钥管理服务或受控配置文件加载新密钥。

备注:内容仅供参考。