PAYATHON 2026

AlipayTradeAppPay 发起支付提示“响应字符串为空”的原因

支付阿杰

结论

alipay.trade.app.pay 的调用方式用错了。APP 支付时,商户服务端应调用 sdkExecute(request) 生成已签名的订单字符串,并把它返回给 APP,而不是通过 certificateExecute(request) 向网关发起普通的服务端请求。

certificateExecute 适用于订单查询等由服务端直接调用支付宝并接收 JSON 响应的接口。如果把它用于 APP 支付,SDK 可能无法取得可解析的响应内容。后续执行到 decryptResponse 时发现 rsp 为空,就会抛出“响应字符串为空”的异常。

示例中的 extend_params 类型也不正确。该字段需要 JSON 对象,不能使用 JSON 数组。

正确的调用方式

DefaultAlipayClient alipayClient = getAlipayClient("APP_ID");

AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
request.setNotifyUrl(payDto.getCallback_url());

JSONObject extendParams = new JSONObject();
extendParams.put("sys_service_provider_id", "MCH_ID");

JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", "20211223114451992");
bizContent.put("total_amount", "0.01");
bizContent.put("subject", "测试支付");
bizContent.put("extend_params", extendParams);

request.setBizContent(bizContent.toString());

// APP 支付应生成订单字符串,而不是通过 certificateExecute 请求网关
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
String orderString = response.getBody();

// 将 orderString 原样返回给 APP
System.out.println(orderString);

APP 收到 orderString 后,将它传给支付宝客户端 SDK 发起支付。这个字符串必须原样使用,不要重新拼接、排序、解码或再次进行 URL 编码,否则可能破坏签名。

为什么查询接口可以正常返回错误

订单查询是服务端到服务端的调用,流程如下:

商户服务端 → 支付宝网关 → 商户服务端

所以查询接口可以使用 certificateExecute,同步接收支付宝返回的业务成功或业务错误信息,例如:

AlipayTradeQueryResponse response =
        alipayClient.certificateExecute(queryRequest);

APP 支付采用另一套流程:

商户服务端生成订单字符串
        ↓
APP 调用支付宝客户端 SDK
        ↓
支付宝完成支付
        ↓
支付宝异步通知商户服务端

sdkExecute 负责生成包含业务参数、公共参数和签名的订单字符串。它不会直接完成支付,也不会同步返回最终交易结果。

extend_params 的格式问题

原代码将 extend_params 包装成了数组:

"extend_params": [
  {
    "sys_service_provider_id": "MCH_ID"
  }
]

通常应传递对象:

"extend_params": {
  "sys_service_provider_id": "MCH_ID"
}

因此,应直接写入 extendParams:

bizContent.put("extend_params", extendParams);

不要写成:

JSONArray jsonArray = new JSONArray();
jsonArray.add(extendParams);
bizContent.put("extend_params", jsonArray);

如果当前不是服务商代调用场景,可以先删除 extend_params,用最小参数集验证支付流程。sys_service_provider_id 的值应根据实际签约情况和服务商配置确定,不能直接使用未经确认的商户号占位值。

建议的定位步骤

1. 确认接口使用的执行方法

APP 支付使用:

alipayClient.sdkExecute(request);

订单查询、退款和退款查询等服务端接口通常使用:

alipayClient.certificateExecute(request);

客户端使用证书模式,不代表所有接口都要改用 certificateExecute。证书模式影响的是身份认证和验签配置,不会改变 APP 支付需要生成订单字符串的调用方式。

2. 检查生成的订单字符串

确认以下内容不为空:

response.getBody()

生成的字符串还应包含类似以下公共参数:

app_id=
method=alipay.trade.app.pay
biz_content=
sign=
sign_type=RSA2

日志可以记录订单号和字符串长度,但生产环境不宜长期打印完整订单字符串、私钥等敏感信息。

3. 使用最小业务参数测试

先只保留必填参数:

JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", "20211223114451992");
bizContent.put("total_amount", "0.01");
bizContent.put("subject", "测试支付");
request.setBizContent(bizContent.toString());

确认支付链路正常后,再加入 extend_params 等可选字段。这样更容易判断问题出在调用方式还是业务参数。

4. 检查客户端初始化配置

使用证书模式时,需要重点确认:

  • appId 是否正确;
  • 应用私钥是否与开放平台上传的应用公钥匹配;
  • 应用公钥证书、支付宝公钥证书和支付宝根证书是否对应当前环境;
  • 网关地址是否与正式环境或沙箱环境一致;
  • 字符集通常应为 UTF-8;
  • 签名算法是否为应用实际配置的 RSA2。

如果证书或签名配置有误,sdkExecute 仍可能生成订单字符串,但 APP 真正调起支付后会被支付宝拒绝。这和当前在 certificateExecute 中出现的“响应字符串为空”并不是同一层面的错误。

注意事项

商户不能只根据 APP 返回值判断支付结果。服务端应以支付宝异步通知为主要依据,完成验签并校验 app_id、订单号、金额和商户身份后,再更新订单状态。必要时,还可以调用交易查询接口主动确认结果。

当前异常应先通过将 certificateExecute(request) 改为 sdkExecute(request) 处理。如果修改后仍然无法支付,再结合 APP 端返回的支付结果码、服务端收到的异步通知和订单查询结果,继续排查签名、证书或业务参数。

备注:内容仅供参考。