支付宝支付二级域名异步回调失败如何排查
明确结论
二级域名本身通常不会导致支付宝异步回调失败。同步跳转正常,只能说明支付请求和同步返回链路基本可用,不能证明支付宝可以访问程序 B 的 notify_url。
建议优先检查以下几项:
- 程序 B 生成的
notify_url是否确实指向二级域名。 - 该地址能否从公网直接访问,是否存在登录、验证码、IP 限制或来源校验。
- 二级域名的 DNS、HTTPS、反向代理和服务器路由是否配置正确。
- 程序 B 是否正确验签,并在处理成功后返回支付宝要求的成功文本。
- 支付宝后台配置、应用、商户号和支付参数是否与程序 B 使用的账号一致。
为什么同步正常、异步失败
支付流程中的同步返回和异步通知是两条不同的链路:
- 同步返回:用户支付完成后,浏览器跳转到
return_url。 - 异步通知:支付宝服务器向商户服务器发起 HTTP 请求,访问
notify_url。
因此,浏览器能够打开二级域名,并不代表支付宝服务器也能访问该地址。常见原因包括:
notify_url仍然写成了程序 A 的一级域名;- 二级域名可以访问首页,但没有配置对应的接口路由;
- Nginx 或 Apache 将二级域名转发到了错误的程序;
- HTTPS 证书不匹配、证书链不完整或 TLS 配置异常;
- 回调地址被登录中间件、CSRF 校验、鉴权组件或 WAF 拦截;
- 回调接口返回了
404、403、500或其他非预期内容; - 程序收到了通知,但验签失败或没有返回
success; - 程序 B 使用了错误的支付宝公钥、应用私钥、
app_id或商户配置; - 回调处理失败后重复执行,导致订单状态或业务逻辑异常。
第一步:确认实际发送的 notify_url
不要只检查配置文件,还应查看程序 B 实际发起支付请求时提交的参数。重点确认:
- 域名是否为程序 B 的二级域名;
- 路径是否正确;
- 是否使用了
https; - 是否包含错误的端口、路径或多余空格;
- 是否被框架中的默认配置覆盖。
例如,支付请求中应明确设置类似参数:
$request->setReturnUrl('https://pay.example.com/alipay/return');
$request->setNotifyUrl('https://pay.example.com/alipay/notify');
接口名称会因支付框架和 SDK 版本而不同,实际项目应以当前 SDK 的接口为准。关键不在于方法名,而在于最终提交给支付宝的 notify_url 值。
可以在发送支付请求前,记录经过脱敏处理的参数:
logger()->info('alipay payment request', [
'app_id' => $request->getAppId(),
'notify_url' => $request->getNotifyUrl(),
'return_url' => $request->getReturnUrl(),
'out_trade_no' => $request->getOutTradeNo(),
]);
不要把私钥、完整签名或敏感用户信息写入日志。
第二步:从公网测试回调地址
在服务器外部网络环境中访问回调地址,例如:
curl -i -X POST \
'https://pay.example.com/alipay/notify' \
-d 'test=1'
重点观察:
- DNS 是否解析到正确服务器;
- 是否能够建立 HTTPS 连接;
- HTTP 状态码是否为
200; - 是否出现
301、302跳转; - 是否返回
403、404或500; - 是否被跳转到登录页;
- 是否被网关或 WAF 拦截。
测试请求没有真实支付宝签名,业务层返回验签失败是正常的。但在网络层和路由层,必须能够到达正确的回调程序。
如果服务器配置了 Nginx,可以检查二级域名对应的站点配置是否指向程序 B:
server {
listen 443 ssl;
server_name pay.example.com;
root /var/www/program-b/public;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
}
}
如果程序使用 PHP-FPM、Node.js、Java 或其他运行环境,fastcgi_pass、反向代理地址和路由写法需要根据实际部署方式调整。
第三步:检查回调接口是否被拦截
异步通知接口通常不适合套用普通网页接口的全部安全中间件。检查程序 B 是否对该路径启用了:
- 用户登录校验;
- CSRF 校验;
- 管理员权限校验;
- 请求来源校验;
- Referer 校验;
- 固定 IP 白名单;
- 强制 JSON 请求头;
- 只允许
GET请求; - 只允许特定 User-Agent;
- WAF 或防火墙拦截。
支付宝通知通常由服务端发起,不能依赖浏览器 Cookie、Referer 或用户登录状态。回调接口应允许接收支付宝发送的 POST 参数,并通过支付宝签名机制完成身份验证。
第四步:检查验签和支付宝配置
程序 B 应使用与当前支付宝应用匹配的配置,至少核对:
app_id;- 商户号;
- 应用私钥;
- 支付宝公钥;
- 签名算法;
- 网关地址;
- 沙箱或正式环境;
- 回调参数中的订单号和金额。
如果程序 A 和程序 B 共用支付框架,不代表两套程序可以直接共用全部配置。尤其要确认程序 B 没有读取程序 A 的环境变量、缓存配置或旧配置文件。
伪代码示例如下:
public function notify()
{
$params = request()->post();
// 具体验签方法以当前支付宝 SDK 为准
$verified = $this->alipayClient->verifyNotify($params);
if (!$verified) {
logger()->warning('alipay notify signature verification failed', [
'out_trade_no' => $params['out_trade_no'] ?? null,
]);
return response('fail', 200);
}
$outTradeNo = $params['out_trade_no'] ?? '';
$tradeStatus = $params['trade_status'] ?? '';
if (in_array($tradeStatus, ['TRADE_SUCCESS', 'TRADE_FINISHED'], true)) {
// 根据订单号查询本地订单
// 校验金额、商户号和应用标识
// 使用事务更新订单状态
// 已完成的订单不得重复发货或重复记账
}
// 确认处理成功后再返回
return response('success', 200);
}
这里的 verifyNotify() 仅用于说明处理流程,实际方法名可能是 SDK 提供的 rsaCheckV1、通知验证器或框架封装方法。不能只凭请求参数中的 trade_status 判断支付成功,仍应先完成验签,并核对订单号、金额、商户和应用信息。
第五步:确认返回内容和状态码
异步回调接口即使已经收到通知,如果返回内容不符合要求,支付宝仍可能认为通知处理失败并继续重试。
检查以下内容:
- HTTP 状态码是否为
200; - 成功处理后,响应正文是否为支付宝 SDK 要求的成功文本,通常是
success; - 是否输出了 HTML、调试信息、异常堆栈或 JSON;
- 是否在返回前发生了重定向;
- 是否因为异常导致连接中断。
建议在回调入口和出口记录日志:
logger()->info('alipay notify received', [
'out_trade_no' => request('out_trade_no'),
'trade_status' => request('trade_status'),
]);
// 验签、校验订单并完成业务处理
logger()->info('alipay notify processed', [
'out_trade_no' => request('out_trade_no'),
]);
return response('success', 200);
生产环境不要直接输出异常堆栈,也不要因为重复通知返回失败。异步通知可能会重试,因此接口必须具备幂等性:同一个 out_trade_no 重复到达时,只能完成一次发货、入账或权益发放。
第六步:检查服务器和应用日志
建议同时查看以下日志:
- Nginx 或 Apache access log;
- Web 服务器 error log;
- 应用日志;
- PHP-FPM、Node.js 或 Java 运行日志;
- WAF、防火墙和负载均衡日志;
- DNS 和证书监控记录。
可以通过请求时间、订单号或回调路径进行关联。通常可以这样判断:
- 完全没有访问日志:优先检查
notify_url、DNS、证书、网络和防火墙; - 有访问日志但返回
404:检查二级域名路由和部署目录; - 返回
403:检查鉴权、WAF、权限和访问控制; - 返回
500:检查应用异常、配置和数据库连接; - 应用收到请求但验签失败:检查支付宝公钥、签名算法、原始参数和环境配置;
- 验签成功但订单未更新:检查订单查询、金额校验、事务和幂等逻辑;
- 业务处理成功但支付宝仍重试:检查响应正文、响应状态码和响应时机。
还需要核对支付宝后台配置的情况
如果使用的是同一个支付宝应用,回调域名是否需要在后台配置,以及配置项的具体名称,取决于所使用的产品、接口和当前平台规则。不能仅凭“已经添加一级域名和二级域名”判断配置一定生效。
应以当前支付产品的官方控制台配置和 SDK 文档为准,并确认:
- 程序 B 使用的
app_id与后台配置属于同一应用; - 正式环境和沙箱环境没有混用;
- 使用的支付产品确实要求配置域名;
- 配置保存后已经生效;
- 域名拼写、协议和端口与实际
notify_url一致。
不过,即使后台配置正确,只要服务器无法访问回调地址、接口返回错误或验签失败,异步通知仍然无法正常完成。
建议的排查顺序
先记录程序 B 最终提交的 notify_url,再从公网使用 curl 测试该地址,随后查看服务器访问日志,确认请求是否到达程序 B。若请求已经到达,再依次检查路由、鉴权中间件、验签、订单校验、幂等处理和最终响应内容。
多数情况下,问题不在于使用一级域名还是二级域名,而在于二级域名没有正确指向程序 B,或者回调接口虽然收到了请求,却没有按照支付宝通知协议完成处理并返回成功。
备注:内容仅供参考。