PHP调用支付宝交易查询API报错,支付接口调用正常
结论
支付接口正常,但交易查询接口报错,通常不代表整个 SDK 不可用。问题多半出在查询接口的调用方法、请求参数或返回值处理上。
支付宝 PHP SDK 的支付接口可能使用 pageExecute()、sdkExecute() 等方法。alipay.trade.query 是普通 OpenAPI,需要通过 execute() 调用,请求类为 AlipayTradeQueryRequest。查询时还要提供有效的 out_trade_no 或 trade_no。
问题中没有具体错误信息和完整代码,因此暂时无法确定唯一原因。可以按下面的顺序检查。
正确的调用示例
下面的示例适用于常见的 AopClient 版支付宝 PHP SDK。不同版本的命名空间和加载方式可能不同,请以项目实际安装的 SDK 为准。
<?php
$aop = new AopClient();
$aop->gatewayUrl = 'https://openapi.alipay.com/gateway.do';
$aop->appId = '你的 APPID';
$aop->rsaPrivateKey = '应用私钥';
$aop->alipayrsaPublicKey = '支付宝公钥';
$aop->signType = 'RSA2';
$aop->postCharset = 'UTF-8';
$aop->format = 'json';
$request = new AlipayTradeQueryRequest();
$bizContent = [
// out_trade_no 和 trade_no 至少提供一个
'out_trade_no' => '你的商户订单号',
];
$request->setBizContent(
json_encode($bizContent, JSON_UNESCAPED_UNICODE)
);
try {
$response = $aop->execute($request);
$node = 'alipay_trade_query_response';
if (!isset($response->$node)) {
throw new RuntimeException(
'支付宝返回结构异常:' .
json_encode($response, JSON_UNESCAPED_UNICODE)
);
}
$result = $response->$node;
if (($result->code ?? '') !== '10000') {
printf(
"查询失败:code=%s,sub_code=%s,msg=%s,sub_msg=%s\n",
$result->code ?? '',
$result->sub_code ?? '',
$result->msg ?? '',
$result->sub_msg ?? ''
);
} else {
printf(
"查询成功:trade_status=%s,trade_no=%s\n",
$result->trade_status ?? '',
$result->trade_no ?? ''
);
}
} catch (Throwable $e) {
echo '调用异常:' . $e->getMessage();
}
如果要使用支付宝交易号查询,可以改成:
$bizContent = [
'trade_no' => '支付宝交易号',
];
支付接口生成请求字符串的方式不能直接用于查询接口。例如:
// 页面支付可能这样调用
$aop->pageExecute($payRequest);
// App 支付可能这样调用
$aop->sdkExecute($payRequest);
// 交易查询应这样调用
$aop->execute($queryRequest);
重点排查项
1. 检查请求类
交易查询接口通常使用:
AlipayTradeQueryRequest
请求类、SDK 命名空间或自动加载配置不正确时,可能出现「类不存在」或接口方法不匹配等异常。
如果项目通过 Composer 加载 SDK,请确认入口文件已经加载:
require_once __DIR__ . '/vendor/autoload.php';
具体命名空间取决于安装的 SDK 包,不要混用不同版本文档中的类名。
2. 确认使用了 execute()
alipay.trade.query 是服务端查询接口,通常应这样调用:
$response = $aop->execute($request);
支付接口能正常调用,只能说明支付请求的生成流程可用,无法证明查询接口使用了正确的执行方法。
3. 检查 biz_content 是否为合法 JSON
建议先构造 PHP 数组,再调用 json_encode():
$bizContent = [
'out_trade_no' => $outTradeNo,
];
$json = json_encode($bizContent, JSON_UNESCAPED_UNICODE);
if ($json === false) {
throw new RuntimeException(
'biz_content JSON 编码失败:' . json_last_error_msg()
);
}
$request->setBizContent($json);
不要手工拼接 JSON。订单号中一旦包含引号、反斜杠或其他特殊字符,手工拼接可能造成格式错误。
4. 确认订单号属于当前应用和环境
查询的订单必须与当前网关、应用和商户配置一致。需要逐项检查:
- 是否使用正式环境网关查询沙箱订单;
- 是否使用沙箱网关查询正式订单;
out_trade_no是否与支付时提交的商户订单号完全一致;- 订单是否由当前
app_id对应的应用创建; - 订单是否刚刚提交,支付宝尚未成功受理;
out_trade_no是否被截断、转换成数字或带有多余空格。
商户订单号最好始终按字符串处理:
$outTradeNo = trim((string) $outTradeNo);
不要用浮点数保存长订单号,否则可能丢失精度。
5. 不要只读取最外层返回对象
查询接口的业务结果一般在以下节点中:
$response->alipay_trade_query_response
各字段的含义如下:
code表示网关或业务处理结果;sub_code表示更具体的错误代码;msg是主错误信息;sub_msg是详细错误说明;trade_status是查询成功后的交易状态。
判断是否成功时,不能只看 $response 是否为空,还要检查业务节点中的 code:
$result = $response->alipay_trade_query_response ?? null;
if ($result === null) {
// 返回结构异常
} elseif (($result->code ?? '') === '10000') {
// 查询成功
} else {
// 根据 sub_code 和 sub_msg 定位业务错误
}
根据错误类型继续定位
如果程序直接抛出 PHP 异常,先检查 SDK 加载、请求类、证书或密钥文件、网络连接和 PHP 扩展。
如果支付宝已经返回 JSON,但 code 不是 10000,请完整记录这些字段:
$logData = [
'code' => $result->code ?? null,
'msg' => $result->msg ?? null,
'sub_code' => $result->sub_code ?? null,
'sub_msg' => $result->sub_msg ?? null,
];
error_log(json_encode($logData, JSON_UNESCAPED_UNICODE));
可以根据错误类型继续检查:
- 签名验证失败:核对应用私钥、支付宝公钥、
app_id和signType; - 参数无效:核对
biz_content、参数名称和 JSON 格式; - 交易不存在:核对订单号、应用归属以及沙箱或正式环境;
- 权限不足:确认应用是否具有对应产品和接口的权限;
- 返回解析失败:检查响应节点名称,以及对象和数组的访问方式。
排查时要保留完整的 code、sub_code、msg、sub_msg 和异常堆栈,但不要在日志中输出应用私钥、支付宝公钥原文或其他敏感凭据。
还需要补充的信息
如果按上述方法仍无法解决,需要补充以下信息:
- 完整错误信息或异常堆栈;
- 查询接口的调用代码;
- SDK 的准确包名和版本;
- 当前使用的是沙箱环境还是正式环境;
- 返回的
code、sub_code、msg和sub_msg; - PHP 版本和 SDK 加载方式。
订单号可以脱敏,密钥必须删除。只说「交易查询 API 报错」,无法判断具体是 PHP 运行异常、签名错误、参数错误、权限问题,还是查询了不属于当前应用的订单。
备注:内容仅供参考。
