PAYATHON 2026

支付宝支付成功后未收到异步回调通知如何排查?

支付阿杰

结论

交易状态已经是 TRADE_SUCCESS,说明支付链路正常。没有收到异步通知,通常有以下几类原因:调用 alipay.trade.create 时没有正确传入通知地址、支付宝无法访问该地址、通知被网关拦截,或者接收程序没有正确记录请求并返回响应。

服务商代调用时,重点检查以下内容:

  • 请求是否实际携带了 notify_url。
  • 是否使用了正确的 app_id 和商户授权令牌 app_auth_token。
  • notify_url 是否可以从公网直接访问。
  • 接口是否能够接收 POST 表单数据。
  • 验签和业务处理成功后,是否返回纯文本 success。

仅凭支付宝交易号 61104119354632320000 和 appid: 2021003173601122,无法判断支付宝是否发送过通知。还需要结合请求报文、支付宝侧的通知记录和服务器访问日志进行排查。

首先检查 notify_url

notify_url 是接口的公共请求参数,不属于业务 JSON。服务商通过 SDK 代调用时,需要在请求对象上设置通知地址,并在执行请求时传入被代调用商户的 app_auth_token。

以 Java SDK 为例:

AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
request.setNotifyUrl("https://pay.example.com/alipay/notify");
request.setBizContent("""
{
  "out_trade_no": "ORDER_202609090001",
  "total_amount": "0.01",
  "subject": "测试订单",
  "buyer_id": "2088xxxxxxxxxxxx"
}
""");

AlipayTradeCreateResponse response =
        alipayClient.execute(request, appAuthToken);

查看实际发往支付宝网关的请求日志,确认其中包含:

method=alipay.trade.create
app_id=2021003173601122
notify_url=https://pay.example.com/alipay/notify
app_auth_token=...

常见错误有:

  • 通知地址只写在本地配置文件中,本次请求并未携带。
  • 把 notify_url 放进了 biz_content。
  • SDK 封装层漏掉了 setNotifyUrl()。
  • 代调用时没有传入 app_auth_token,或者传入了其他商户的授权令牌。
  • 多套环境使用了不同配置,生产请求却带上了测试环境的地址。

注意区分 return_url 和 notify_url。return_url 用于客户端同步跳转,不能代替服务端异步通知。

检查通知地址能否被支付宝访问

通知地址必须是支付宝服务器可以访问的公网 HTTP 或 HTTPS 地址。排查时需要注意:

  1. 域名能否在公网解析,解析结果是否正确。
  2. 服务器的 80 或 443 端口是否开放。
  3. HTTPS 证书是否有效,证书链是否完整,证书域名是否匹配。
  4. 防火墙、WAF、CDN 或反向代理是否拦截了支付宝的 POST 请求。
  5. 地址是否仅允许内网访问,或者要求固定来源 IP、登录态、客户端证书。
  6. 接口是否返回 301 或 302 跳转。
  7. 接口是否响应超时,或者返回 4xx、5xx。
  8. 路由是否只接受 GET,无法处理 POST。

排查时可以同时查看:

  • CDN 或负载均衡访问日志
  • Nginx、Apache 等 Web 服务器日志
  • 应用网关日志
  • 接口应用日志
  • WAF 和防火墙拦截日志

如果最外层访问日志中完全找不到对应请求,先检查请求是否传入了 notify_url,再检查 DNS、网络入口和安全策略。如果网关记录了请求,但应用没有收到,则继续检查路由、代理转发和请求体解析。

正确接收并处理通知

支付宝通常通过 POST 发送异步通知,内容类型为 application/x-www-form-urlencoded,不能按 JSON 请求体解析。

在 Java Servlet/Spring 环境中,可以先收集全部表单参数,再使用支付宝 SDK 验签:

@PostMapping(
    value = "/alipay/notify",
    consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE
)
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,
            alipayPublicKey,
            "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");
        String sellerId = params.get("seller_id");

        // 进一步校验 app_id、seller_id、out_trade_no、total_amount。
        // 使用 out_trade_no 或 trade_no 做幂等更新。
        // 只有业务处理成功后才能返回 success。

        return "success";
    } catch (AlipayApiException e) {
        return "failure";
    }
}

实际项目还应记录通知参数和处理结果,但日志中不要写入私钥、完整授权令牌等敏感信息。

检查验签配置

如果服务器收到了请求,但程序仍判定处理失败,问题通常出在验签配置或参数处理上:

  • 验签应使用支付宝公钥,不能使用应用私钥或应用公钥。
  • sign_type 通常是 RSA2,具体应以实际通知参数和应用配置为准。
  • 字符集应与请求配置一致,常见值是 UTF-8。
  • 验签前不要修改参数值、重新编码或丢弃空格。
  • 不要手工把 sign、sign_type 拼入待验签字符串,建议直接使用官方 SDK。
  • 不要混用证书模式和普通公钥模式。

验签通过后,仍需完成业务校验,包括核对:

app_id
seller_id
out_trade_no
trade_no
total_amount
trade_status

app_id 应与本次调用使用的应用一致,seller_id 应属于实际收款商户,订单号和金额也必须与本地订单一致。

必须返回纯文本 success

只有验签和业务处理都成功后,接口才能返回:

success

响应正文不能包含 JSON、HTML、空格或其他说明。下面这种响应可能不会被识别为成功:

{"code":200,"message":"success"}

数据库事务尚未提交时,也不要提前返回 success。如果业务处理失败,应返回 success 以外的内容,让支付宝按其通知策略继续尝试。

同一通知可能重复到达,因此订单更新必须具备幂等性:

UPDATE payment_order
SET pay_status = 'PAID',
    alipay_trade_no = ?
WHERE out_trade_no = ?
  AND pay_status <> 'PAID';

推荐排查顺序

  1. 打印并核对创建交易时的完整公共请求参数,确认其中有正确的 notify_url。
  2. 确认代调用使用的是目标商户对应的 app_auth_token。
  3. 通过支付宝开放平台相关工具或账单、交易查询能力,确认交易所属的应用和商户。
  4. 查询支付宝侧是否有异步通知发送记录。具体入口名称可能会随开放平台后台调整。
  5. 查看 CDN、负载均衡和 Web 服务器访问日志,判断请求是否已经到达。
  6. 如果请求已经到达,检查 HTTP 状态码、表单解析、验签结果和业务异常。
  7. 确认处理成功后的响应体严格为 success。
  8. 修复后创建新订单重新测试。历史交易能否重发通知,应以开放平台当前提供的重发能力为准。

订单查询返回 TRADE_SUCCESS 时,可以据此进行补偿处理,但不能用主动查询代替异步通知。生产系统应增加主动查询或定时补偿任务。对于长时间停留在待支付状态的订单,调用交易查询接口,并在核对订单号、商户、金额和交易状态后进行幂等补单。

备注:内容仅供参考。