PAYATHON 2026

海外付款后支付宝支付成功回调来自国内还是海外

支付阿杰

结论

支付成功后的异步回调由支付宝服务器发起,与用户使用的浏览器、手机以及用户所在的国家或地区无关。

用户在海外打开国内创建的支付链接并完成付款后,回调通常不会改由海外用户所在地的设备发出。回调使用什么出口,取决于支付宝所接入的支付产品、服务器部署和网络路由,与付款人的实际位置没有直接关系。

因此,不能根据用户的付款地点推断回调 IP,也不应把“回调一定来自国内 IP”作为业务判断条件。

原因

支付宝支付通常包含两类通知:

  • 同步跳转:支付完成后,用户浏览器会跳转到 return_url。该请求可能经过用户所在地区的网络,不能作为确认支付成功的可靠依据。
  • 异步通知:支付宝服务器向商户配置的 notify_url 发起 HTTP/HTTPS 请求。商户通常根据这类服务器间通信更新订单状态。

异步通知来自支付宝的服务端基础设施。即使用户在海外付款,用户设备也只负责完成支付操作,不会向商户服务器发送支付宝异步通知。

不过,“由支付宝服务器发起”并不意味着回调会长期使用某个固定的国内 IP。实际出口地址可能随产品类型、接入主体、网络调度或基础设施调整而变化。如果需要配置 IP 白名单,应根据当前接入产品的支付宝官方文档和商户平台配置,确认是否有官方维护的 IP 范围。

正确处理方式

1. 确保支付宝可以访问回调地址

notify_url 应满足以下条件:

  • 使用公网可以访问的域名。
  • 建议使用证书有效的 HTTPS。
  • 不依赖用户登录状态、Cookie 或浏览器环境。
  • 无需人工验证、验证码或二次跳转。
  • 防火墙、WAF 和反向代理允许支付宝的通知请求到达接口。
  • 接口应在合理时间内处理完请求,耗时任务可以交给消息队列异步执行。

如果服务器只允许来自中国大陆网络的访问,需要根据实际接入产品确认支付宝的通知出口能否访问该服务器,不能根据用户的付款地点决定是否放行。

2. 验证支付宝签名

判断回调是否可信,主要依靠签名验证,不能只检查来源 IP。验签时需要使用支付宝公钥,并确保参与验签的参数内容与收到的通知一致。

以下是使用支付宝 Java SDK 的示意代码:

@PostMapping("/payment/alipay/notify")
public String handleAlipayNotify(HttpServletRequest request) throws Exception {
    Map<String, String> params = new HashMap<>();

    request.getParameterMap().forEach((key, values) -> {
        params.put(key, String.join(",", values));
    });

    boolean verified = AlipaySignature.rsaCheckV1(
        params,
        alipayPublicKey,
        "UTF-8",
        "RSA2"
    );

    if (!verified) {
        return "failure";
    }

    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");

    // 校验订单号、商户身份、金额等业务字段
    Order order = orderService.findByOrderNo(outTradeNo);
    if (order == null) {
        return "failure";
    }

    if (!order.getExpectedAmount().toPlainString().equals(totalAmount)) {
        return "failure";
    }

    if ("TRADE_SUCCESS".equals(tradeStatus)
            || "TRADE_FINISHED".equals(tradeStatus)) {
        // 必须保证幂等,避免重复通知导致重复入账或重复发货
        orderService.markPaidIfUnpaid(outTradeNo, tradeNo);
    }

    return "success";
}

支付宝 SDK 不同版本的方法签名可能不同,请以项目实际使用版本的文档为准。无论使用哪种语言,都需要完成以下检查:

  1. 验证通知签名。
  2. 校验 app_id、seller_id 等商户身份字段,具体字段由接入产品决定。
  3. 确认 out_trade_no 属于当前商户。
  4. 确认 total_amount 与本地订单金额一致。
  5. 确认 trade_status 是业务认可的成功状态。
  6. 使用幂等更新,避免重复回调引发重复处理。

3. 必要时主动查询订单

网络超时、防火墙拦截或服务异常都可能导致异步通知延迟。如果订单长时间没有收到通知,可以调用相应的支付宝交易查询接口,核实订单的最终状态。

例如,部分支付宝开放平台产品使用:

alipay.trade.query

具体接口名称、请求字段和状态含义,请以所接入支付产品的官方文档为准。

注意事项

  • 不要直接根据客户端同步跳转结果确认支付成功。
  • 不要根据请求 IP 所在的国家或地区判断订单是否合法。
  • 除非支付宝明确提供并维护对应产品的通知 IP 范围,否则不要只依赖单个固定 IP 白名单。
  • 即使配置了 IP 白名单,仍需验证签名并校验业务字段。
  • 支付宝可能重复发送异步通知,因此订单处理必须具备幂等性。
  • 如果验签失败、金额不一致或订单不存在,不应把订单更新为已支付。
  • 只有业务处理成功后,才能返回支付宝要求的成功响应,例如纯文本 success。具体响应格式以接入产品文档为准。

备注:内容仅供参考。