调用支付宝退款接口返回 ILLEGAL_CLIENT_IP,白名单无效
结论
ILLEGAL_CLIENT_IP 表示支付宝网关识别到的请求来源公网 IP 不在该退款接口对应商户账号的允许列表中。白名单里应填写服务器经过 NAT、代理或网关后的实际出口公网 IP,不能填写服务器内网 IP,也不能填写支付宝账号 2088001842589142。
如果实际出口 IP 已正确加入白名单,但接口仍然报错,请重点检查:
- 白名单是否配置在请求参数
partner对应的商户身份下; - 请求是否会随机经过多个公网出口;
- 退款接口权限和 IP 白名单是否属于同一个签约产品;
- 白名单修改是否已经生效;
- 生产请求是否误用了沙箱或其他应用、商户的配置。
这些项目都确认无误后,需要联系支付宝技术支持,并提供请求时间和响应内容,以便核查服务端识别到的 IP 及白名单记录。
为什么加入白名单后仍会报错
支付宝校验的是建立 HTTPS 连接时看到的来源 IP。这个地址不一定与应用服务器上的本机地址相同。
例如:
应用服务器:10.0.1.20
NAT 网关:203.0.113.10
支付宝看到的来源 IP:203.0.113.10
在这种情况下,将 10.0.1.20 加入白名单没有作用,必须配置 203.0.113.10。
常见原因如下:
-
填写了内网 IP
10.x.x.x、172.16.x.x~172.31.x.x、192.168.x.x等私有地址不会成为互联网请求的来源公网 IP。 -
存在多个出口 IP
集群、负载均衡、NAT 网关、容器平台或多线路机房可能让退款请求经由不同的公网 IP 发出。如果只添加其中一个 IP,部分请求会成功,部分请求仍会失败。
-
请求经过正向代理或云网关
如果应用通过代理访问外部网络,支付宝看到的是代理服务器的出口 IP,不是应用服务器的 IP。
-
白名单配置到了错误的商户或产品
MAPI 请求中的
partner必须与配置白名单的支付宝商户身份一致。登录账号、签约账号、应用账号和合作伙伴身份不一致时,容易把白名单配错位置。 -
请求实际由其他机器发出
开发人员检查的可能是 Web 服务器 IP,但退款任务实际上由定时任务服务器、消息队列消费者或独立财务服务器执行。
-
旧接口权限或配置异常
https://mapi.alipay.com/gateway.do是旧版 MAPI 网关。商户能否继续使用该接口,取决于原有的签约权限。持有账号或密钥,不代表已经开通相应的退款产品。
排查步骤
1. 确认请求中的商户身份
记录最终发送到网关的请求参数,重点检查:
partner
service
seller_id 或 seller_email
_input_charset
sign_type
partner 应当是签约该退款接口的合作伙伴身份。如果请求中使用 2088001842589142,白名单也必须配置在该身份对应的商户和退款产品下。
除了代码中的默认配置,还要检查运行环境里的环境变量、配置中心和部署参数,确认生产实例没有加载另一套商户配置。
2. 确认真实出口公网 IP
请在实际执行退款请求的服务器或容器中检查出口地址,不要在开发电脑或其他同网段服务器上查询。
如果基础设施由运维团队或云平台管理,可以直接核对:
- NAT 网关绑定的弹性公网 IP;
- 正向代理的出口公网 IP;
- Kubernetes 节点或集群的 SNAT 地址;
- 多可用区和容灾线路使用的全部出口地址。
将查询结果与支付宝白名单逐项比较。如果每次查询得到的地址不同,说明当前出口不固定。此时需要先固定出口 IP,或者按照支付宝的规则,将所有可能使用的出口 IP 加入白名单。
3. 绕过代理做对照测试
先检查系统和运行环境是否设置了代理:
env | grep -i proxy
使用 curl 时,还要检查是否设置了:
CURLOPT_PROXY
CURLOPT_INTERFACE
如果业务条件允许,可以在同一台服务器上临时绕过代理,发起一次对照请求。如果绕过代理后错误消失,白名单中应配置代理的出口 IP,或者让退款流量通过固定的直连出口访问支付宝。
4. 检查请求链路
整理完整的请求链路:
退款程序
→ 容器或虚拟机
→ 正向代理(如有)
→ NAT 网关
→ 公网
→ mapi.alipay.com
白名单应包含支付宝在最后一跳看到的公网 IPv4 地址。负载均衡的公网 IP 通常用于接收入站流量,不一定是服务器访问支付宝时使用的出口 IP。
5. 检查白名单状态
进入对应商户和签约产品的管理页面,确认:
- IP 已经保存成功;
- 配置没有处于待审核或未生效状态;
- 填写的是正确的公网 IP;
- 配置中没有格式错误、空格或错误网段;
- 当前配置对应生产环境。
不同时期签约的 MAPI 产品可能使用不同的配置入口。具体位置应以商户后台实际显示的内容或支付宝技术支持的说明为准。
6. 保留完整响应信息
记录请求时间、接口名和支付宝返回的原始响应,但不要把密钥、私钥或完整签名原文写入日志。例如:
<?php
$log = [
'time' => date('c'),
'gateway' => 'https://mapi.alipay.com/gateway.do',
'service' => $params['service'] ?? null,
'partner' => $params['partner'] ?? null,
'http_code' => $httpCode,
'response' => $responseBody,
];
error_log(
json_encode($log, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)
);
联系支付宝技术支持时,通常需要准备:
- 合作伙伴身份
partner; - 调用的
service; - 精确到秒的请求时间;
- 实际出口公网 IP;
- 完整错误码和响应报文;
- 请求是否经过 NAT 或代理;
- 白名单配置页面截图。
PHP 请求示例
下面的示例只演示如何记录网络请求和响应,不包含具体退款接口的业务参数和签名实现。参数名称应以商户已签约接口的文档为准。
<?php
$gateway = 'https://mapi.alipay.com/gateway.do';
$params = [
'service' => '实际签约接口的 service 值',
'partner' => '2088001842589142',
'_input_charset' => 'utf-8',
'sign_type' => '实际使用的签名类型',
'sign' => '按照对应接口规范生成的签名',
// 其他退款业务参数
];
$ch = curl_init($gateway);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($params, '', '&', PHP_QUERY_RFC3986),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
]);
$response = curl_exec($ch);
$curlError = curl_error($ch);
$httpCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
error_log(json_encode([
'time' => date('c'),
'partner' => $params['partner'],
'service' => $params['service'],
'http_code' => $httpCode,
'curl_error' => $curlError,
'response' => $response,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
添加 client_ip、return_url 或自定义 HTTP 请求头,都不能改变支付宝看到的 TCP 来源 IP,也无法绕过白名单校验。这个问题必须从网络出口层面处理。
注意事项
- 不要通过反复修改签名算法来处理
ILLEGAL_CLIENT_IP。这个错误首先指向来源 IP 校验,签名问题通常会返回其他错误码。 - 不要将商户私钥、MD5 Key、应用私钥或完整签名参数提交到公开渠道。
- 固定出口 IP 后,还要考虑故障切换线路。备用 NAT 网关的公网 IP 也需要加入配置。
- 如果退款服务运行在弹性容器、Serverless 或动态公网环境中,应通过固定 NAT 网关统一出口。
mapi.alipay.com的旧接口参数和权限不能与新版开放平台接口直接混用。如果原签约产品已经不可用,应根据支付宝后台提供的能力迁移到对应的开放平台退款接口,不能只替换网关地址。- 白名单与实际出口 IP 完全一致后,如果接口仍持续返回该错误,通常无法只通过客户端代码定位。请携带调用时间、
partner、出口 IP 和完整响应,联系支付宝技术支持核查。
备注:内容仅供参考。
