PAYATHON 2026

Alipay Easy SDK 如何接收支付回调结果?

支付小周

结论

Alipay Easy SDK 提供了用于验证支付异步通知签名的方法:

Factory.Payment.Common().verifyNotify(parameters)

该方法用于确认支付宝回调数据的签名是否可信,返回值为 boolean。它不会接收 HTTP 请求,也不会将回调内容转换成统一的支付结果对象。应用需要自行读取回调请求中的参数,并在验签通过后,从参数集合中获取 trade_status、out_trade_no、trade_no 等业务字段。

处理步骤

  1. 在服务端配置一个支付宝可以访问的 notify_url。
  2. 读取支付宝 POST 请求中的全部表单参数。
  3. 将参数整理成 Map<String, String>。
  4. 调用 verifyNotify 验证签名。
  5. 验签通过后,核对订单号、金额、商户身份和交易状态。
  6. 业务处理完成后,向支付宝返回纯文本 success。

Java 示例

下面的示例使用 Servlet API。Spring Boot 项目可以采用不同的参数获取方式,但调用验签方法时,仍需传入支付宝回调中的完整参数集合。

import com.alipay.easysdk.factory.Factory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public void alipayNotify(
        HttpServletRequest request,
        HttpServletResponse response) throws IOException {

    Map<String, String> parameters = new HashMap<>();

    request.getParameterMap().forEach((name, values) -> {
        if (values != null && values.length > 0) {
            parameters.put(name, String.join(",", values));
        }
    });

    try {
        boolean verified = Factory.Payment.Common()
                .verifyNotify(parameters);

        if (!verified) {
            response.getWriter().write("failure");
            return;
        }

        String tradeStatus = parameters.get("trade_status");
        String outTradeNo = parameters.get("out_trade_no");
        String tradeNo = parameters.get("trade_no");
        String totalAmount = parameters.get("total_amount");
        String appId = parameters.get("app_id");
        String sellerId = parameters.get("seller_id");

        // 必须结合本地订单进行业务校验:
        // 1. outTradeNo 是否存在
        // 2. totalAmount 是否与订单金额一致
        // 3. appId、sellerId 是否属于当前商户
        // 4. 订单是否已经处理,避免重复入账
        // 5. tradeStatus 是否为业务允许的状态

        if ("TRADE_SUCCESS".equals(tradeStatus)
                || "TRADE_FINISHED".equals(tradeStatus)) {

            // 使用事务或幂等机制更新订单状态
            // updateOrderIfNotPaid(outTradeNo, tradeNo, totalAmount);
        }

        response.getWriter().write("success");
    } catch (Exception e) {
        // 验签或业务处理异常时,不应返回 success
        response.getWriter().write("failure");
    }
}

在 Spring MVC 中,也可以直接接收参数:

@PostMapping("/alipay/notify")
@ResponseBody
public String alipayNotify(@RequestParam Map<String, String> parameters) {
    try {
        boolean verified = Factory.Payment.Common()
                .verifyNotify(parameters);

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

        String tradeStatus = parameters.get("trade_status");
        String outTradeNo = parameters.get("out_trade_no");
        String tradeNo = parameters.get("trade_no");
        String totalAmount = parameters.get("total_amount");

        // 校验订单信息并进行幂等处理

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

如何获取回调结果

verifyNotify 只验证签名。回调结果需要从传入的 parameters 中读取,例如:

String tradeStatus = parameters.get("trade_status");
String outTradeNo = parameters.get("out_trade_no");
String tradeNo = parameters.get("trade_no");
String totalAmount = parameters.get("total_amount");

常见字段有:

  • trade_status:支付宝交易状态。
  • out_trade_no:商户订单号。
  • trade_no:支付宝交易号。
  • total_amount:订单金额。
  • app_id:支付宝应用 ID。
  • seller_id:收款方支付宝用户 ID。

不同支付产品的字段可能有所区别,具体应以当前产品的异步通知协议为准。

注意事项

验签通过后仍需校验订单

验签通过只能说明通知带有可信签名。修改订单前,还要核对:

  • out_trade_no 是否对应本地订单;
  • total_amount 是否与本地订单金额一致;
  • app_id 和 seller_id 是否符合预期;
  • trade_status 是否属于需要处理的成功状态。

回调处理必须幂等

支付宝可能多次发送同一笔交易的通知。重复回调不能导致重复发货、充值或记账。通常可以根据订单状态、支付宝交易号或数据库唯一约束来保证幂等。

验签前不要修改参数

应将支付宝回调中的完整原始参数传给 verifyNotify。验签前不要删除 sign、sign_type,也不要修改参数值或重新编码,否则可能造成验签失败。

业务处理完成后再返回 success

接口应返回以下纯文本:

success

如果验签未通过、订单校验失败或业务事务尚未完成,不应返回 success。否则,支付宝可能将该通知视为已经正确处理。

同步跳转不能代替异步通知

用户关闭页面或网络中断,都可能导致浏览器的同步跳转无法完成。因此,订单最终状态应主要以服务端异步通知为准,必要时还可以调用交易查询接口进行补偿确认。

备注:内容仅供参考。