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 端返回的支付结果码、服务端收到的异步通知和订单查询结果,继续排查签名、证书或业务参数。
备注:内容仅供参考。
