PAYATHON 2026

支付宝支付后异步通知地址为空且后台未收到通知

支付小周

结论

“异步通知”查询结果中的“通知地址”为空,并不能说明支付宝已经向正确的 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。
  • 是否强制要求客户端证书。
  • 请求是否被限流,或被识别为攻击流量。
  • 反向代理路由是否已经发布到生产环境。

可以按网络链路依次查看这些日志:

  1. CDN 或云负载均衡访问日志。
  2. WAF 和防火墙拦截日志。
  3. Nginx、Apache 或 API Gateway 日志。
  4. 应用服务器访问日志。
  5. 支付回调业务日志。

如果最外层入口没有任何记录,问题通常不在应用控制器内部。如果网关有记录而应用没有记录,则应继续检查路由、鉴权和代理配置。

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_no
  • out_trade_no
  • POST
  • 4xx、5xx
  • TLS 握手、路由失败和连接超时记录

如果请求已经到达入口,应记录实际 HTTP 状态码和响应内容,再根据状态码继续定位:

  • 301/302:通知地址发生了跳转。
  • 400:请求解析、参数或网关规则异常。
  • 401/403:请求被鉴权、WAF 或访问控制拦截。
  • 404:回调路由不存在,或发布路径错误。
  • 405:接口不允许 POST。
  • 415:接口不接受表单 Content-Type。
  • 429:请求被限流。
  • 5xx:应用或上游服务异常。
  • 超时:处理时间过长、网络不通,或连接没有正常结束。

第三步:验证公网可达性

从生产内网以外的环境访问通知地址,检查:

  • DNS 是否解析到正确的生产入口。
  • HTTPS 证书是否可信,证书链是否完整。
  • POST 请求能否直接到达接口。
  • 接口是否无需登录即可访问。
  • 请求过程中是否不会发生跳转。
  • 接口能否快速返回明确的 HTTP 响应。

第四步:核对回调代码和日志策略

业务日志中没有通知记录,不能直接证明请求没有到达。请求可能在进入业务方法之前,就被过滤器、鉴权组件或网关拒绝。

建议在回调入口增加安全的访问日志,至少记录:

  • 接收时间
  • 请求路径
  • 来源链路信息
  • app_id
  • trade_no
  • out_trade_no
  • 验签结果
  • 订单校验结果
  • 最终响应结果

不要在日志中完整记录所有支付参数、个人信息或密钥。

第五步:提交支付宝侧核查

如果已经确认以下情况:

  • 原始请求中的 notify_url 格式和位置正确;
  • 支付产品支持异步通知;
  • 通知地址可以从公网访问;
  • CDN、WAF、网关和应用均无访问记录;
  • 诊断工具仍显示通知地址为空,并且没有 HTTP 状态码;

那么商户侧已经很难继续定位。应向支付宝技术支持提供以下信息,请其核查交易创建参数的实际解析结果和通知投递记录:

  • 应用 ID:2021004192691734
  • 支付宝交易号:2025070822001499231459009828
  • 外部订单号:FL202507072353442245079
  • 通知记录时间:2025-07-08 14:54:02
  • 调用的具体支付接口名称
  • 脱敏后的最终请求报文
  • 诊断工具截图
  • 商户侧入口日志查询结果
  • 通知域名及公网连通性测试结果

请支持人员重点确认:

  1. 该笔交易是否保存了有效的 notify_url。
  2. 系统是否实际生成过通知任务。
  3. 通知投递时解析出的目标地址是什么。
  4. 是否发生过投递失败,以及对应的 HTTP 状态码或网络错误。
  5. “通知地址为空”究竟是数据未落库、页面展示异常,还是请求参数没有生效。

注意事项

  • 异步通知应作为处理支付结果的主要入口,前台同步跳转不能代替异步通知。
  • 回调处理必须保证幂等,因为同一笔交易可能收到多次通知。
  • 必须验签,并核对 app_id、订单号、金额、商户身份和交易状态。
  • 不能只根据通知参数更新任意订单。应先查询本地订单,再完成关联校验。
  • 如果长时间没有收到通知,可以主动调用交易查询接口补偿订单状态,但主动查询不能代替对通知链路的排查。
  • 不要只凭诊断工具中的“通知地址为空”得出结论。最终判断需要结合实际请求参数、入口访问日志、HTTP 状态码和支付宝侧投递记录。

备注:内容仅供参考。