支付宝沙箱 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
查询请求必须使用生成这笔交易的沙箱应用及其对应密钥。需要逐项核对:
- SDK 中的
app_id是否为9021000137678503。 - 应用私钥是否确实属于这个沙箱应用。
- 验签所用的支付宝公钥是否来自同一个沙箱应用配置。
- 当前沙箱卖家账号是否对应
seller_id=2088721036902118。 - 是否同时存在多套配置、旧配置或环境变量覆盖。
- 如果使用服务商代调用,
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
建议的排查顺序
- 确认查询地址是
https://openapi.alipaydev.com/gateway.do。 - 使用回调中的
trade_no=2024072222001402120503337044查询。 - 输出查询接口返回的完整
code、sub_code、sub_msg和原始响应。 - 检查运行时加载的
app_id,确认它没有被环境变量或其他配置覆盖。 - 重新核对应用私钥和支付宝公钥所对应的沙箱应用。
- 核对沙箱卖家身份是否为
seller_id=2088721036902118。 - 检查是否错误携带了
app_auth_token。 - 确认实际发送的
out_trade_no与0722171031-6259逐字符一致。 - 如果配置完全一致,可以间隔数秒进行有限次数的重试,排除沙箱短暂同步延迟。
如果 trade_no 和 out_trade_no 始终都查不到,应优先检查查询客户端是否使用了错误的沙箱网关、密钥或商户授权上下文,而不是直接认定订单不存在。
备注:内容仅供参考。
