PAYATHON 2026

支付宝沙箱 alipay.trade.query 查询交易不存在

支付老李

结论

回调中已经包含 trade_status=TRADE_SUCCESS、正确的 out_trade_no 和支付宝交易号 trade_no。这说明该交易确实存在于发送回调的支付宝沙箱商户环境中。

此时,如果 alipay.trade.query 返回“交易不存在”,通常不是订单号格式有误,而是查询请求与原支付交易不在同一套上下文中。建议检查以下内容:

  • 查询接口是否使用沙箱网关;
  • 查询使用的 app_id、应用私钥和支付宝公钥是否属于同一个沙箱应用;
  • 查询所对应的沙箱卖家账号是否与回调中的 seller_id 一致;
  • 是否误传了 app_auth_token,或使用了另一套代调用授权;
  • SDK 最终发送的 out_trade_no 是否与回调值完全一致。

只确认 app_id 相同还不够。

先用 trade_no 交叉查询

回调中已经给出了支付宝交易号:

trade_no = 2024072222001402120503337044

可以先用这个字段查询:

{
  "trade_no": "2024072222001402120503337044"
}

再用商户订单号查询:

{
  "out_trade_no": "0722171031-6259"
}

alipay.trade.query 支持使用 trade_no 或 out_trade_no 查询,通常传入其中一个即可。

可以根据查询结果继续判断:

  • trade_no 能查到,但 out_trade_no 查不到:检查程序实际发送的商户订单号,特别留意空格、引号、截断、字符替换和取错订单记录等问题。
  • 两种方式都查不到:检查网关、密钥、卖家身份和应用授权上下文。
  • 稍后重试可以查到:可能是沙箱环境出现了短暂的同步延迟。可以增加有限次数的延迟重试,但不要用无限重试掩盖配置错误。

检查查询网关

沙箱请求必须发送到沙箱网关:

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

不能发送到正式环境网关:

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

一种常见情况是,支付流程使用了沙箱配置,但查询接口初始化了另一套客户端,仍然连接正式环境或另一个沙箱应用。

排查时应记录 SDK 最终使用的请求地址,不要只看配置文件中的地址。

核对完整的商户身份

回调中的身份信息如下:

app_id      = 9021000137678503
auth_app_id = 9021000137678503
seller_id   = 2088721036902118

查询请求必须使用生成这笔交易的沙箱应用及其对应密钥。需要逐项核对:

  1. SDK 中的 app_id 是否为 9021000137678503。
  2. 应用私钥是否确实属于这个沙箱应用。
  3. 验签所用的支付宝公钥是否来自同一个沙箱应用配置。
  4. 当前沙箱卖家账号是否对应 seller_id=2088721036902118。
  5. 是否同时存在多套配置、旧配置或环境变量覆盖。
  6. 如果使用服务商代调用,app_auth_token 是否属于实际收款商户。

即使 app_id 字符串相同,也不能说明运行时使用的私钥、网关和授权令牌一定正确。

如果不是服务商代调用模式,不要随意携带 app_auth_token。错误的授权上下文可能会让查询落到另一个商户身份下。

Java 查询示例

下面使用回调中的 trade_no 查询。不同版本的支付宝 Java SDK 在类名上可能略有差异,请以项目实际依赖为准。

AlipayClient alipayClient = new DefaultAlipayClient(
    "https://openapi.alipaydev.com/gateway.do",
    "9021000137678503",
    APP_PRIVATE_KEY,
    "json",
    "UTF-8",
    ALIPAY_PUBLIC_KEY,
    "RSA2"
);

AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("""
{
  "trade_no": "2024072222001402120503337044"
}
""");

AlipayTradeQueryResponse response = alipayClient.execute(request);

System.out.println("code=" + response.getCode());
System.out.println("subCode=" + response.getSubCode());
System.out.println("subMsg=" + response.getSubMsg());
System.out.println("body=" + response.getBody());

if (response.isSuccess()) {
    System.out.println("tradeStatus=" + response.getTradeStatus());
    System.out.println("outTradeNo=" + response.getOutTradeNo());
    System.out.println("tradeNo=" + response.getTradeNo());
}

如果使用 out_trade_no 查询:

AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("""
{
  "out_trade_no": "0722171031-6259"
}
""");

AlipayTradeQueryResponse response = alipayClient.execute(request);

不要把订单号再次序列化成带引号的字符串。下面这个实际值是错误的:

"\"0722171031-6259\""

正确值应为:

0722171031-6259

输出完整响应信息

排查时不要只输出“交易不存在”,还应记录支付宝返回的完整字段:

code
msg
sub_code
sub_msg
body

如果返回:

sub_code = ACQ.TRADE_NOT_EXIST

说明支付宝在当前查询身份和环境下没有找到这笔交易,但不一定意味着回调中的订单号不存在。

同时记录以下非敏感信息:

gateway
app_id
是否携带 app_auth_token
out_trade_no
trade_no
请求时间

不要把私钥、签名原文和授权令牌写入日志。

检查回调的真实性

只有验签成功后,才能使用回调参数。验签时应使用支付宝公钥,并验证支付宝实际发送的全部待验签参数。不能只根据 app_id 或 trade_status 判断通知是否可信。

验签成功后,再检查:

app_id
seller_id
out_trade_no
total_amount
trade_status

其中金额应与本地订单一致:

total_amount = 0.02

业务处理成功后,向支付宝返回:

success

建议的排查顺序

  1. 确认查询地址是 https://openapi.alipaydev.com/gateway.do。
  2. 使用回调中的 trade_no=2024072222001402120503337044 查询。
  3. 输出查询接口返回的完整 code、sub_code、sub_msg 和原始响应。
  4. 检查运行时加载的 app_id,确认它没有被环境变量或其他配置覆盖。
  5. 重新核对应用私钥和支付宝公钥所对应的沙箱应用。
  6. 核对沙箱卖家身份是否为 seller_id=2088721036902118。
  7. 检查是否错误携带了 app_auth_token。
  8. 确认实际发送的 out_trade_no 与 0722171031-6259 逐字符一致。
  9. 如果配置完全一致,可以间隔数秒进行有限次数的重试,排除沙箱短暂同步延迟。

如果 trade_no 和 out_trade_no 始终都查不到,应优先检查查询客户端是否使用了错误的沙箱网关、密钥或商户授权上下文,而不是直接认定订单不存在。

备注:内容仅供参考。