api_alipay_trade_query 支付成功后查询 response 为空
结论
out_trade_no 与支付宝页面显示的商家订单号一致,不一定能查到交易。alipay.trade.query 只能查询当前调用环境和授权主体下的订单。
常见原因包括:
- 支付与查询使用了不同的
app_id。 - 一个请求走沙箱环境,另一个走正式环境。
- 支付和查询使用的支付宝商户账号、应用授权或
app_auth_token不一致。 out_trade_no在生成、存储或读取过程中发生了变化。- SDK 未正确解析或输出支付宝的原始响应。
即使订单不存在,支付宝通常也会返回包含 code、sub_code、sub_msg 等字段的业务响应。如果返回的确实是 None、空字符串或空字典,应先检查 SDK 调用和响应解析,不能只核对订单号。
优先检查调用环境
支付请求和查询请求必须使用完全相同的配置:
app_id
gateway
seller/account
sign_type
app_auth_token(代商户调用时)
尤其要核对网关地址:
正式环境:https://openapi.alipay.com/gateway.do
沙箱环境:https://openapi-sandbox.dl.alipaydev.com/gateway.do
沙箱订单无法在正式环境中查询,正式订单也无法在沙箱环境中查询。
如果系统部署了多个支付宝应用,还要确认查询时没有误读其他应用的 app_id、私钥或配置文件。商家订单号只需在特定商户或应用范围内保持唯一,并不是支付宝的全局唯一标识。
同时使用 trade_no 排查
支付成功后,支付宝会生成交易号 trade_no。如果能从同步返回、异步通知或支付宝商家后台取得该字段,可以直接用它查询:
result = alipay.api_alipay_trade_query(
trade_no=alipay_trade_no
)
print(result)
如果使用 trade_no 可以查到交易,而使用 out_trade_no 查不到,应重点核对本地保存的订单号与发起支付时实际提交的值是否完全一致。
可以输出带边界的日志,以免漏掉空格或类型差异:
print("out_trade_no =", repr(out_trade_no))
print("type =", type(out_trade_no))
print("length =", len(str(out_trade_no)))
常见问题包括:
- 订单号前后带有空格或换行。
- 数据库字段长度不足,导致订单号被截断。
- 数字型订单号被转换成科学计数法,或丢失前导零。
- 重试支付时生成了新订单号,查询仍使用旧值。
- 查询时误传了支付平台流水号,而不是发起支付时的
out_trade_no。
订单号应始终按字符串处理:
out_trade_no = str(out_trade_no).strip()
检查 SDK 返回值和原始响应
不同 Python SDK 处理返回值的方式并不相同。有的直接返回字典,有的返回 JSON 字符串,还有的会在验签失败或业务失败时抛出异常。
如果使用的 SDK 提供 api_alipay_trade_query 方法,可以先完整记录返回结果:
try:
response = alipay.api_alipay_trade_query(
out_trade_no=str(out_trade_no).strip()
)
print("response type:", type(response))
print("response:", repr(response))
except Exception as exc:
print("query failed:", repr(exc))
raise
排查时不要直接读取某个可能不存在的字段,例如:
# 不建议在排查阶段直接这样写
trade_status = response.get("trade_status")
业务查询失败时,响应中可能没有 trade_status,但通常会包含错误信息。应先检查完整响应:
if not response:
raise RuntimeError("支付宝查询返回为空,请检查 HTTP 请求、SDK 解析和日志")
code = response.get("code")
if code != "10000":
print("code:", code)
print("msg:", response.get("msg"))
print("sub_code:", response.get("sub_code"))
print("sub_msg:", response.get("sub_msg"))
else:
print("trade_no:", response.get("trade_no"))
print("out_trade_no:", response.get("out_trade_no"))
print("trade_status:", response.get("trade_status"))
使用官方风格的 Python SDK 时,调用形式通常类似:
import json
from alipay.aop.api.request.AlipayTradeQueryRequest import (
AlipayTradeQueryRequest,
)
request = AlipayTradeQueryRequest()
request.biz_content = {
"out_trade_no": str(out_trade_no).strip()
}
raw_response = alipay_client.execute(request)
print("raw_response:", repr(raw_response))
response = json.loads(raw_response)
query_response = response.get("alipay_trade_query_response", {})
print("code:", query_response.get("code"))
print("sub_code:", query_response.get("sub_code"))
print("sub_msg:", query_response.get("sub_msg"))
print("trade_status:", query_response.get("trade_status"))
具体类名和返回类型由所使用的 SDK 及版本决定,应以当前 SDK 接口为准。
代商户调用时检查授权主体
如果服务商应用代商户发起支付,查询时通常也要使用与支付时相同的商户授权上下文,例如同一个 app_auth_token。
response = alipay.api_alipay_trade_query(
out_trade_no=out_trade_no,
app_auth_token=app_auth_token
)
该 SDK 方法是否直接接收上述参数,需要查阅实际使用的 SDK 文档。无论采用哪种传参方式,都不能由商户 A 完成支付,再使用商户 B 的授权信息查询。
还要确认授权没有失效,并查看支付宝返回的 sub_code 和 sub_msg,避免把授权错误误判为“没有订单”。
不要把支付页面跳转当成最终成功
用户跳转到支付成功页面,不能单独证明交易已经完成。订单状态仍应通过异步通知或 alipay.trade.query 确认。
查询成功后,应重点判断 trade_status:
trade_status = response.get("trade_status")
if trade_status in ("TRADE_SUCCESS", "TRADE_FINISHED"):
print("支付成功")
elif trade_status == "WAIT_BUYER_PAY":
print("等待买家付款")
elif trade_status == "TRADE_CLOSED":
print("交易已关闭")
else:
print("未知或未返回交易状态:", trade_status)
如果刚完成支付便立即查询,可以进行有限次数的短间隔重试,以应对网络链路或状态同步延迟,但不要无限轮询:
import time
for attempt in range(3):
response = alipay.api_alipay_trade_query(
out_trade_no=out_trade_no
)
if response and response.get("code") == "10000":
break
time.sleep(1)
这种重试只能处理短暂延迟,无法解决 app_id、环境或商户主体不一致的问题。
建议的排查顺序
- 从支付请求日志中取得实际提交的
out_trade_no。 - 从异步通知或商家后台取得支付宝
trade_no。 - 使用
trade_no查询一次,确认交易所属主体。 - 对比支付和查询使用的
app_id、网关及app_auth_token。 - 使用
repr()输出订单号,排除空格、截断和类型转换问题。 - 记录查询接口的完整原始响应、异常和 HTTP 状态。
- 检查是否误从响应外层读取字段,或在解析 JSON 前就开始取值。
- 如果原始 HTTP 响应也为空,再检查网络代理、超时、SDK 版本兼容性和请求签名配置。
排查时不能只看“订单号是否相同”。还要确认订单是否由当前查询所使用的同一环境、同一应用和同一商户授权主体创建,并取得接口返回的完整错误信息。
备注:内容仅供参考。
