alipay.trade.query 查询交易订单时验签失败
结论
支付可以正常发起,但 alipay.trade.query 返回“验签失败”,通常有两个原因:EasySDK 中的 alipayPublicKey 配置错误,或者应用使用的是证书模式,程序却按普通公钥模式配置。
支付页面能打开,基本可以说明商户私钥生成的请求签名可用。但调用 alipay.trade.query 时,SDK 还要用支付宝公钥验证同步响应。因此,支付宝公钥配置有误时,问题往往会在查询接口中出现。
重点检查配置
普通公钥模式涉及以下密钥:
merchantPrivateKey:商户应用私钥,用于为请求签名。alipayPublicKey:支付宝公钥,用于验证支付宝返回的数据。- 应用公钥:由应用私钥推导并上传到支付宝开放平台,不能填入
alipayPublicKey。
最常见的配置错误,是把“应用公钥”当成“支付宝公钥”。请登录支付宝开放平台,在当前应用的接口加签配置中复制平台生成的“支付宝公钥”。
还要确认以下配置来自同一个应用和同一套环境:
appId- 商户应用私钥
- 上传到开放平台的应用公钥
- 支付宝公钥
- 网关地址
正式环境与沙箱环境的密钥和应用 ID 不能混用。
普通公钥模式配置示例
下面以 Java EasySDK 为例。不同版本的 EasySDK 可能使用不同的字段名称,请以项目实际依赖提供的 API 为准:
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
public class AlipayConfig {
public static void init() {
Config config = new Config();
config.protocol = "https";
config.gatewayHost = "openapi.alipay.com";
config.signType = "RSA2";
config.appId = "你的应用AppId";
// 商户应用私钥,不是公钥,也不是支付宝公钥
config.merchantPrivateKey =
"MIIEvQIBADANBgkqhkiG9w0BAQEFA...";
// 从支付宝开放平台获取的“支付宝公钥”
// 不要填写应用公钥
config.alipayPublicKey =
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...";
Factory.setOptions(config);
}
}
查询订单时,应传入创建交易时使用的商户订单号:
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse;
public class AlipayQueryService {
public AlipayTradeQueryResponse query(String outTradeNo) throws Exception {
AlipayTradeQueryResponse response =
Factory.Payment.Common().query(outTradeNo);
if ("10000".equals(response.code)) {
return response;
}
throw new IllegalStateException(
"查询失败,code=" + response.code
+ ", subCode=" + response.subCode
+ ", msg=" + response.msg
+ ", subMsg=" + response.subMsg
);
}
}
如果要查询的是支付宝交易号,需要先确认当前 EasySDK 方法是否支持传入 trade_no。不要把支付宝交易号传给只接收 out_trade_no 的方法。
如果应用使用证书模式
如果开放平台中的接口加签方式是“公钥证书”,仅配置普通的 alipayPublicKey 并不够。通常还需要配置:
- 应用公钥证书
- 支付宝公钥证书
- 支付宝根证书
- 与证书匹配的应用私钥
示意配置如下:
Config config = new Config();
config.protocol = "https";
config.gatewayHost = "openapi.alipay.com";
config.signType = "RSA2";
config.appId = "你的应用AppId";
config.merchantPrivateKey = "你的应用私钥";
config.merchantCertPath = "/path/to/appCertPublicKey.crt";
config.alipayCertPath = "/path/to/alipayCertPublicKey_RSA2.crt";
config.alipayRootCertPath = "/path/to/alipayRootCert.crt";
Factory.setOptions(config);
具体使用哪些证书字段,以及字段是否支持文件路径、资源路径或证书文本,要看所用 EasySDK 的语言和版本。不要把 .crt 文件的内容直接填入普通公钥字段。
排查顺序
1. 确认验签失败发生在哪一侧
先区分以下两种情况:
- 支付宝响应
isv.invalid-signature等错误:通常表示支付宝无法验证请求签名,应检查应用私钥、应用公钥、appId和signType。 - EasySDK 收到响应后抛出“验签失败”:通常表示本地无法验证支付宝响应,应优先检查
alipayPublicKey或证书配置。
不要只关注 HTTP 400。还应记录异常中的 code、subCode、msg、subMsg 和支付宝请求 ID,但不要在日志中输出完整私钥。
2. 核对密钥是否成套
可以用当前应用私钥重新导出应用公钥,再与支付宝开放平台中配置的应用公钥比对。如果两者不一致,需要上传正确的应用公钥,并同步更新程序配置。
之后重新获取该应用对应的支付宝公钥。历史应用、其他应用和沙箱应用的支付宝公钥都不能混用。
3. 检查密钥格式
常见的格式问题包括:
- 私钥中含有多余的空格、引号或转义字符。
- 环境变量中的换行符被写成字面量
\n。 - 密钥内容不完整。
- PKCS#1、PKCS#8 格式与当前 SDK 的要求不一致。
- 把公钥证书内容当作普通 RSA 公钥使用。
signType配置为RSA,但开放平台实际使用RSA2。
如果密钥存放在 YAML、JSON 或环境变量中,还要确认程序加载后的字符串没有被截断。
4. 核对网关环境
正式环境通常使用:
openapi.alipay.com
沙箱环境通常使用:
openapi.alipaydev.com
具体地址仍应以当前支付宝开放平台配置和所用 SDK 文档为准。沙箱的 appId、应用私钥和支付宝公钥必须全部来自沙箱,不能与正式环境的配置混用。
5. 确认初始化只执行一次
如果 Factory.setOptions(config) 设置的是全局配置,就应避免在不同业务代码中重复初始化。在多应用或多商户场景中,后一次初始化可能覆盖前一次配置,造成支付使用一套密钥,而查询使用另一套密钥。
为什么支付正常仍会查询验签失败
部分支付接口只生成支付表单或支付链接。这个过程中,EasySDK 主要使用商户私钥为请求签名,不一定会立即验证支付宝返回的同步业务响应。
alipay.trade.query 是服务端同步接口。支付宝返回查询结果后,SDK 通常还会使用支付宝公钥验签。因此:
支付能够发起
≠
支付宝响应验签配置正确
可以先把 alipayPublicKey 替换为当前应用、当前环境对应的支付宝公钥。如果应用采用证书模式,则应改用完整的证书模式配置。多数“支付正常、查询验签失败”的问题都出在这两处。
备注:内容仅供参考。
