PAYATHON 2026

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 替换为当前应用、当前环境对应的支付宝公钥。如果应用采用证书模式,则应改用完整的证书模式配置。多数“支付正常、查询验签失败”的问题都出在这两处。

备注:内容仅供参考。