PAYATHON 2026

电脑网站支付和网页扫码支付成功后查询提示交易不存在

支付老李

结论

40004 / ACQ.TRADE_NOT_EXIST 的含义是:支付宝没有在当前查询请求对应的商户、应用和运行环境中找到指定交易。

页面显示“支付成功”,不能证明查询条件一定正确。常见原因包括:

  • 支付和查询使用的 app_id、商户账号或密钥配置不一致;
  • 支付发生在正式环境,查询请求却发往沙箱环境,或者相反;
  • 查询使用的 out_trade_no 与创建支付时传入的值不完全一致;
  • 页面只是根据 return_url 显示支付成功,并未通过异步通知或查询结果确认交易状态;
  • 查询时间太早,交易数据还未完成同步;
  • 实际支付成功的是另一笔订单,业务系统却关联了错误的订单号。

排查时,建议优先使用支付宝在支付成功后返回的 trade_no 查询,同时核对支付、回调和查询三个环节使用的应用配置。

返回码代表什么

交易查询接口可能返回:

{
  "code": "40004",
  "msg": "Business Failed",
  "subCode": "ACQ.TRADE_NOT_EXIST",
  "subMsg": "交易不存在"
}

各字段的含义如下:

  • code = 40004 表示请求已经到达支付宝,但业务处理失败;
  • subCode = ACQ.TRADE_NOT_EXIST 表示在当前查询范围内没有找到对应交易;
  • 金额字段为 0.00,不代表发生过一笔零元交易。这通常只是未查询到有效交易数据时返回的字段值。

这类错误通常不是签名错误。签名或密钥无法通过校验时,一般会返回签名、权限或参数类错误。但签名通过也不代表应用配置正确。如果查询使用了另一个应用的有效密钥,仍可能收到“交易不存在”的结果。

按顺序排查

1. 核对支付和查询使用的订单号

先确认查询请求中的 out_trade_no 与创建支付请求时传入的值逐字符一致,尤其要检查:

  • 大小写是否一致;
  • 前后是否有空格;
  • 内容是否被截断;
  • 是否误用了本地数据库主键;
  • 重试支付时是否生成了新的订单号;
  • 是否把退款单号、支付流水号或其他业务编号当成了商户订单号。

例如,支付时传入:

P202504191538401

查询时也必须传入完全相同的值。

建议在生成支付请求前记录原始 biz_content。后续查询时,应从同一条订单记录中读取 out_trade_no,不要根据时间或其他字段重新拼接。

2. 优先使用支付宝交易号查询

如果同步跳转参数或异步通知中已经包含支付宝交易号 trade_no,优先用它查询。trade_no 是支付宝生成的交易标识,定位具体交易通常比本地订单号更直接。

查询参数示例:

{
  "trade_no": "支付宝返回的交易号"
}

如果使用 trade_no 可以查到交易,而使用 out_trade_no 查不到,应检查本地订单号的保存、映射和读取过程。

不要把 out_trade_no 的值传入 trade_no 字段。两者的含义不同:

{
  "out_trade_no": "商户订单号",
  "trade_no": "支付宝交易号"
}

通常填写其中一个即可,具体要求以当前使用的 SDK 和接口文档为准。

3. 核对 app_id 和商户主体

支付请求、异步通知验签和交易查询应使用同一套应用配置。至少需要核对:

app_id
应用私钥
支付宝公钥或支付宝公钥证书
app_cert_sn
alipay_root_cert_sn
签约商户账号

常见的配置问题有:

  • 混用了测试配置和生产配置;
  • 多个应用共用同一份配置文件;
  • 支付服务和查询服务部署在不同机器上,环境变量不一致;
  • 更新证书或密钥后,部分服务仍在读取旧配置;
  • 服务商模式下,支付和查询使用的授权商户信息不一致;
  • 支付由应用 A 发起,查询却由应用 B 发起。

在不泄露私钥的前提下,可以为每次支付和查询记录以下信息:

app_id
网关地址
out_trade_no
trade_no
请求时间
请求 ID 或链路 ID
部署环境
商户主体标识

4. 检查正式环境和沙箱环境

确认支付请求和查询请求发往同一个环境。

常见情况包括:

  • 支付请求发往正式网关,查询请求却发往沙箱网关;
  • 前端打开的是正式收银台,后端查询服务仍在加载测试配置;
  • 本地、测试和生产环境使用了相同订单号,排查时看错了数据环境。

沙箱和正式环境的数据彼此隔离。即使 out_trade_no 完全相同,也无法跨环境查询。

5. 不要只相信同步跳转页面

电脑网站支付完成后,浏览器通常会跳转到商户配置的 return_url。这个页面主要用于向用户展示结果,不能作为最终入账依据,因为:

  • 用户可能直接构造或重复访问页面地址;
  • 浏览器跳转可能丢失或中断;
  • 页面代码可能只要进入成功路由就显示“支付成功”;
  • 同步参数可能属于另一笔订单;
  • 页面显示成功时,服务端可能还没有完成订单状态更新。

服务端应按以下步骤确认支付结果:

  1. 验证支付宝异步通知的签名;
  2. 核对通知中的 app_id、out_trade_no、total_amount 和商户信息;
  3. 检查 trade_status;
  4. 必要时调用交易查询接口复核;
  5. 所有校验通过后,再更新本地订单状态。

异步通知的典型判断逻辑如下:

if (signVerified
        && expectedAppId.equals(notifyAppId)
        && expectedOutTradeNo.equals(outTradeNo)
        && expectedAmount.compareTo(totalAmount) == 0
        && ("TRADE_SUCCESS".equals(tradeStatus)
            || "TRADE_FINISHED".equals(tradeStatus))) {
    // 使用幂等事务更新订单状态
}

这段代码只用于说明校验思路。验签方法和字段获取方式应以当前使用的支付宝 SDK 为准。

6. 检查是否查询得过早

支付完成后立即查询,少数情况下会遇到短暂的数据同步延迟。此时可以进行有限次数的延迟重试,例如:

第 1 次:立即查询
第 2 次:2 秒后
第 3 次:5 秒后
第 4 次:10 秒后

示例伪代码:

int[] delays = {0, 2, 5, 10};

for (int delay : delays) {
    if (delay > 0) {
        Thread.sleep(delay * 1000L);
    }

    TradeQueryResult result = queryTrade(outTradeNo);

    if (result.isTradeFound()) {
        return result;
    }

    if (!"ACQ.TRADE_NOT_EXIST".equals(result.getSubCode())) {
        throw new RuntimeException("查询失败:" + result.getSubCode());
    }
}

throw new RuntimeException("多次查询仍不存在,需要核对应用、环境和订单号");

不要无限重试。如果数十秒后仍持续返回 ACQ.TRADE_NOT_EXIST,应检查订单号、应用身份和运行环境,而不是继续轮询。

交易查询示例

以下是使用 Java SDK 的结构示例。不同 SDK 版本的类名可能略有差异,应以项目的实际依赖为准:

AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();

AlipayTradeQueryModel model = new AlipayTradeQueryModel();
model.setOutTradeNo("P202504191538401");

// 如果已经取得支付宝交易号,也可以改为:
// model.setTradeNo("支付宝交易号");

request.setBizModel(model);

AlipayTradeQueryResponse response = alipayClient.execute(request);

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

初始化客户端时,需要确认配置来自发起支付的同一个应用:

AlipayClient alipayClient = new DefaultAlipayClient(
    gatewayUrl,
    appId,
    merchantPrivateKey,
    "json",
    "UTF-8",
    alipayPublicKey,
    "RSA2"
);

如果项目采用证书模式,应使用对应的证书客户端配置,不能混用普通公钥模式和证书模式的参数。

建议增加的日志

支付、通知和查询日志应能通过 out_trade_no 串联,便于快速定位问题。可以记录:

{
  "stage": "trade_query",
  "environment": "production",
  "app_id": "实际使用的应用 ID",
  "out_trade_no": "P202504191538401",
  "trade_no": "",
  "gateway": "实际请求的网关",
  "code": "40004",
  "sub_code": "ACQ.TRADE_NOT_EXIST",
  "request_time": "实际请求时间",
  "trace_id": "业务链路标识"
}

日志中不要保存应用私钥、完整签名密钥、用户付款密码等敏感信息。

还需要检查数据库中是否存在异常记录:

SELECT
    out_trade_no,
    trade_no,
    payment_status,
    app_id,
    payment_channel,
    created_at,
    paid_at
FROM payment_order
WHERE out_trade_no = 'P202504191538401';

表名和字段名应按实际系统调整。检查时重点关注订单号是否被覆盖、是否关联到错误的应用,以及是否存在重复订单记录。

如何判断问题位于哪一环

可以根据查询结果缩小排查范围:

  • trade_no 能查到,out_trade_no 查不到:本地订单号的保存或映射可能有误。
  • 两种编号都查不到,但支付宝账单中存在交易:优先检查 app_id、商户主体、授权关系和网关环境。
  • 支付宝账单中也不存在交易:页面上的“支付成功”很可能不是可靠的服务端支付结果。
  • 稍后重试可以查到:可能存在短暂的同步延迟,应增加有次数上限的重试机制。
  • 只有某台服务器查不到:对比各节点的配置文件、环境变量、证书和发布时间。
  • 只有服务商代商户场景查不到:检查支付和查询是否使用了同一个授权商户身份。

注意事项

  • 不要根据前端成功页面直接发货或充值。
  • 处理异步通知时必须验签,并校验订单号、金额、应用和商户身份。
  • 更新订单时应保证幂等,避免重复通知造成重复发货。
  • out_trade_no 应在对应业务范围内保持唯一。支付重试时,不要随意复用已经用于其他交易的编号。
  • 不要通过修改本地订单状态掩盖查询失败。应先确认支付宝侧是否存在真实交易。
  • 如果已经确认订单号、trade_no、应用、商户主体和环境全部一致,但接口仍稳定返回 ACQ.TRADE_NOT_EXIST,应整理完整请求时间、app_id、脱敏后的订单号、支付宝 trade_no、网关环境和接口响应,再通过支付宝开放平台的技术支持渠道核查。

备注:内容仅供参考。