alipay.trade.order.settle 返回 ACQ.INVALID_PARAMETER,如何正确传递 ro
结论
royalty_parameters 的类型传错了。
在 biz_content 中,它应当是一个 JSON 数组,每个数组元素是一条分账明细。当前请求却把整个数组再次编码成了字符串:
"royalty_parameters":"[{\"trans_in\":\"2088441108413251\",\"amount\":0.1}]"
支付宝解析这个字段后得到的是字符串,而不是分账明细数组,所以返回 ACQ.INVALID_PARAMETER。正确结构如下:
"royalty_parameters":[
{
"trans_in":"2088441108413251",
"amount":"0.10",
"desc":"系统利润分账"
}
]
问题原因
当前代码很可能先对分账明细执行了 json_encode(),之后又对整个 biz_content 执行了一次 json_encode()。
下面的写法就会造成双重 JSON 编码:
$bizContent = [
'royalty_parameters' => json_encode($royaltyParameters),
];
$bizContentJson = json_encode($bizContent);
这样一来,royalty_parameters 就会变成带引号和转义符的 JSON 字符串。URL 解码无法解决这个问题,因为错误出在 biz_content 的数据结构中,而不是 URL 编码环节。
将该字段清空后仍然报错也很正常,因为空字符串同样不是合法的分账明细数组。没有分账明细时,应直接省略这个参数;需要分账时,则必须传入至少一条有效明细。
正确的 PHP 写法
先将分账明细保留为 PHP 数组,最后再统一编码整个 biz_content:
<?php
$royaltyParameters = [
[
'trans_in' => '2088441108413251',
'amount' => '0.10',
'desc' => '系统利润分账',
],
];
$bizContent = [
'out_request_no' => 'settle20230310100142342351963',
'trade_no' => '2023031022001455411432403300',
'royalty_parameters' => $royaltyParameters,
'extend_params' => [
'royalty_finish' => true,
],
'royalty_mode' => 'async',
];
$bizContentJson = json_encode(
$bizContent,
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
if ($bizContentJson === false) {
throw new RuntimeException(json_last_error_msg());
}
生成的 biz_content 应类似下面这样:
{
"out_request_no": "settle20230310100142342351963",
"trade_no": "2023031022001455411432403300",
"royalty_parameters": [
{
"trans_in": "2088441108413251",
"amount": "0.10",
"desc": "系统利润分账"
}
],
"extend_params": {
"royalty_finish": true
},
"royalty_mode": "async"
}
如果使用支付宝官方 SDK,直接将这段 JSON 设置为 biz_content,不要再单独编码 royalty_parameters:
$request = new AlipayTradeOrderSettleRequest();
$request->setBizContent($bizContentJson);
$result = $aopClient->execute($request);
具体类名可能因 PHP SDK 版本而异,但处理方式相同:业务对象组装完成后,只对整个 biz_content 编码一次。
如果必须自行拼接请求
自行构造网关请求时,按以下顺序处理:
- 使用原始参数值组装待签名字符串。
- 对参数签名。
- 对参数名和参数值进行 URL 编码。
- 发送请求。
不要先进行 URL 编码再签名,也不要让 URL 编码后的 biz_content 重新参与签名。使用官方 SDK 通常更稳妥,可以避免参数排序、字符集、空值过滤和签名编码不一致等问题。
还需要检查的事项
修正 JSON 类型后,如果接口仍然返回参数错误,可以逐项检查:
royalty_parameters必须是数组,不能是字符串、空字符串或对象。- 每条分账明细都应包含有效的
trans_in和amount。 - 金额建议使用字符串形式,例如
"0.10",以免浮点数在程序处理过程中产生精度问题。 trans_in必须是符合当前分账产品要求的有效收入方账号,并满足相应的签约、绑定或分账关系要求。- 不需要的
operator_id、空的app_auth_token等参数应省略,不要传入null或空字符串。 out_request_no应保持幂等。同一次分账重试使用同一个请求号,新的分账请求使用新的请求号。- 分账金额、交易状态、可分账余额以及
royalty_finish的使用条件,还要以当前接入产品和接口文档为准。
发送请求前直接查看 biz_content,就能判断是否已经修正。如果 royalty_parameters 后面紧跟着 [,说明结构正确;如果后面是带引号的 "[{\"...,说明仍然存在重复编码。
备注:内容仅供参考。
