支付宝支付后异步通知地址为空且后台未收到通知
结论
“异步通知”查询结果中的“通知地址”为空,并不能说明支付宝已经向正确的 notify_url 发起请求,也不能据此判断问题出在业务代码。
现有信息只能证明下单请求日志中出现过 notify_url。还需确认支付宝交易接口是否实际接收并启用了该参数,以及支付宝通知服务器能否访问这个地址。排查时可优先检查参数是否有效、网络入口日志、HTTP 状态码和支付宝侧的通知记录。
如果诊断页面没有显示 HTTP 状态码,服务器、网关和 WAF 也都没有访问记录,可能是通知没有实际发出、通知地址没有生效,或者诊断工具的展示或数据记录存在异常。此时需要联系支付宝技术支持,提供应用 ID、交易号和通知时间,请其核查服务端记录。
可能原因
1. notify_url 出现在日志中,但没有实际生效
日志中记录了这个参数,不代表它已经作为公共请求参数成功提交。常见情况有:
notify_url被放进了业务参数biz_content,而不是接口的公共请求参数。- 使用 SDK 时,日志只记录了本地组装的请求对象,实际执行请求前却没有调用
setNotifyUrl()。 - URL 前后含有空格、换行或不可见字符。
- URL 编码或拼接有误,支付宝无法识别。
- 当前支付产品或调用方式不支持该场景下的异步通知。
- 实际支付交易不是由当前检查的请求创建,例如发生了重复支付、订单重建,或者调用链路混用了不同订单。
以 Java SDK 为例,通知地址通常需要设置在请求对象上:
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setReturnUrl("https://www.example.com/pay/return");
request.setNotifyUrl("https://api.example.com/alipay/notify");
request.setBizContent(bizContent);
AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
不要只把通知地址写入 biz_content:
{
"out_trade_no": "FL202507072353442245079",
"total_amount": "100.00",
"subject": "订单支付",
"notify_url": "https://api.example.com/alipay/notify"
}
这种写法是否有效,要以具体接口的定义为准。如果接口将 notify_url 定义为公共参数,就应通过 SDK 对应的方法或公共请求参数传递。
2. 通知地址无法从公网访问
支付宝异步通知是由支付宝服务器主动请求商户服务器,因此通知地址必须能从公网直接访问。以下地址通常无法正常接收通知:
localhost或127.0.0.1- 局域网 IP
- 只能通过 VPN 或企业内网访问的域名
- 必须登录,或者依赖 Cookie、额外鉴权才能访问的接口
- 被防火墙、WAF、CDN、安全组或 IP 白名单拦截的地址
应从商户网络之外测试接口:
curl -i -X POST 'https://api.example.com/alipay/notify' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data 'out_trade_no=test&trade_status=TRADE_SUCCESS'
这项测试只能检查公网连通性和接口响应,不能模拟带有有效支付宝签名的通知。
3. HTTPS、DNS 或网关配置异常
如果通知地址使用 HTTPS,还应检查:
- SSL/TLS 证书是否过期。
- 证书链是否完整。
- 域名是否解析到了正确地址。
- 是否发生 HTTP 301/302 跳转。
- 网关是否只允许特定的
User-Agent。 - 是否强制要求客户端证书。
- 请求是否被限流,或被识别为攻击流量。
- 反向代理路由是否已经发布到生产环境。
可以按网络链路依次查看这些日志:
- CDN 或云负载均衡访问日志。
- WAF 和防火墙拦截日志。
- Nginx、Apache 或 API Gateway 日志。
- 应用服务器访问日志。
- 支付回调业务日志。
如果最外层入口没有任何记录,问题通常不在应用控制器内部。如果网关有记录而应用没有记录,则应继续检查路由、鉴权和代理配置。
4. 接口收到通知,但没有正确处理表单请求
支付宝异步通知一般通过 HTTP POST 发送表单参数,接口不能默认按 JSON 请求体解析。如果接口只接受 application/json,可能会返回 400、404、415 或其他错误。
Spring Boot 接收示例:
@PostMapping(
value = "/alipay/notify",
consumes = "application/x-www-form-urlencoded"
)
@ResponseBody
public String alipayNotify(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
request.getParameterMap().forEach((key, values) -> {
params.put(key, String.join(",", values));
});
try {
boolean verified = AlipaySignature.rsaCheckV1(
params,
ALIPAY_PUBLIC_KEY,
"UTF-8",
"RSA2"
);
if (!verified) {
return "failure";
}
String appId = params.get("app_id");
String outTradeNo = params.get("out_trade_no");
String tradeNo = params.get("trade_no");
String tradeStatus = params.get("trade_status");
String totalAmount = params.get("total_amount");
// 1. 校验 app_id 是否属于当前应用
// 2. 根据 out_trade_no 查询本地订单
// 3. 校验订单金额、商户身份等关键数据
// 4. 幂等更新订单状态
// 5. 业务处理全部成功后返回 success
return "success";
} catch (Exception e) {
// 记录异常及必要的通知标识,避免记录敏感数据
return "failure";
}
}
完成验签、订单核对和状态更新后,接口才能返回以下纯文本:
success
不要返回 JSON、HTML 或包含额外字符的内容,例如:
{"status":"success"}
业务尚未处理成功时,也不要提前返回 success。
建议的排查步骤
第一步:核对创建交易时的原始请求
应以实际发送给支付宝的请求为准,逐项确认:
- 接口名称和支付产品是否支持异步通知。
notify_url是否位于接口规定的位置。- URL 是否含有空格、换行或二次编码。
- SDK 执行请求前是否已经正确设置
notify_url。 - 当前支付交易是否确实由这次请求创建。
- 生产环境配置是否被测试环境配置覆盖。
日志可以记录脱敏后的最终 URL 及其长度,以便发现不可见字符:
String notifyUrl = configuredNotifyUrl == null
? null
: configuredNotifyUrl.trim();
log.info(
"alipay notify url={}, length={}",
notifyUrl,
notifyUrl == null ? 0 : notifyUrl.length()
);
第二步:查询所有入口层日志
以通知时间 2025-07-08 14:54:02 为中心,适当扩大查询范围,同时留意服务器之间的时区差异。依次检查 CDN、负载均衡、WAF、Nginx 和应用日志。
重点搜索以下内容:
- 回调 URL 路径
trade_noout_trade_noPOST4xx、5xx- TLS 握手、路由失败和连接超时记录
如果请求已经到达入口,应记录实际 HTTP 状态码和响应内容,再根据状态码继续定位:
301/302:通知地址发生了跳转。400:请求解析、参数或网关规则异常。401/403:请求被鉴权、WAF 或访问控制拦截。404:回调路由不存在,或发布路径错误。405:接口不允许 POST。415:接口不接受表单 Content-Type。429:请求被限流。5xx:应用或上游服务异常。- 超时:处理时间过长、网络不通,或连接没有正常结束。
第三步:验证公网可达性
从生产内网以外的环境访问通知地址,检查:
- DNS 是否解析到正确的生产入口。
- HTTPS 证书是否可信,证书链是否完整。
- POST 请求能否直接到达接口。
- 接口是否无需登录即可访问。
- 请求过程中是否不会发生跳转。
- 接口能否快速返回明确的 HTTP 响应。
第四步:核对回调代码和日志策略
业务日志中没有通知记录,不能直接证明请求没有到达。请求可能在进入业务方法之前,就被过滤器、鉴权组件或网关拒绝。
建议在回调入口增加安全的访问日志,至少记录:
- 接收时间
- 请求路径
- 来源链路信息
app_idtrade_noout_trade_no- 验签结果
- 订单校验结果
- 最终响应结果
不要在日志中完整记录所有支付参数、个人信息或密钥。
第五步:提交支付宝侧核查
如果已经确认以下情况:
- 原始请求中的
notify_url格式和位置正确; - 支付产品支持异步通知;
- 通知地址可以从公网访问;
- CDN、WAF、网关和应用均无访问记录;
- 诊断工具仍显示通知地址为空,并且没有 HTTP 状态码;
那么商户侧已经很难继续定位。应向支付宝技术支持提供以下信息,请其核查交易创建参数的实际解析结果和通知投递记录:
- 应用 ID:
2021004192691734 - 支付宝交易号:
2025070822001499231459009828 - 外部订单号:
FL202507072353442245079 - 通知记录时间:
2025-07-08 14:54:02 - 调用的具体支付接口名称
- 脱敏后的最终请求报文
- 诊断工具截图
- 商户侧入口日志查询结果
- 通知域名及公网连通性测试结果
请支持人员重点确认:
- 该笔交易是否保存了有效的
notify_url。 - 系统是否实际生成过通知任务。
- 通知投递时解析出的目标地址是什么。
- 是否发生过投递失败,以及对应的 HTTP 状态码或网络错误。
- “通知地址为空”究竟是数据未落库、页面展示异常,还是请求参数没有生效。
注意事项
- 异步通知应作为处理支付结果的主要入口,前台同步跳转不能代替异步通知。
- 回调处理必须保证幂等,因为同一笔交易可能收到多次通知。
- 必须验签,并核对
app_id、订单号、金额、商户身份和交易状态。 - 不能只根据通知参数更新任意订单。应先查询本地订单,再完成关联校验。
- 如果长时间没有收到通知,可以主动调用交易查询接口补偿订单状态,但主动查询不能代替对通知链路的排查。
- 不要只凭诊断工具中的“通知地址为空”得出结论。最终判断需要结合实际请求参数、入口访问日志、HTTP 状态码和支付宝侧投递记录。
备注:内容仅供参考。
