PAYATHON 2026

支付宝同步回调缺少 trade_status 时如何判断支付状态?

支付小周

明确结论

收到同步回调,并不能说明订单已经支付成功。

支付宝同步回调是浏览器页面跳转通知,主要作用是把用户从收银台带回商户页面。即使回调参数验签通过,也只能证明参数来自支付宝且没有被篡改,不能代替支付结果确认。

订单状态应以下列结果为准:

  1. 支付宝异步通知中的 trade_status;
  2. 主动调用 alipay.trade.query 查询到的 trade_status。

同步回调可以用来展示支付结果页面,但不能直接触发发货、充值、开通会员等业务操作。

为什么同步回调不能作为支付成功依据

同步回调依赖用户浏览器完成跳转,存在不少不确定因素:

  • 用户支付后直接关闭页面,商户可能收不到同步回调;
  • 浏览器跳转可能因网络中断、拦截等原因失败;
  • 用户可能重复刷新或再次访问回调地址;
  • 回调地址可能被人为构造或重放;
  • 同步参数中有 trade_no,不代表交易一定已经支付成功;
  • 验签成功只能证明参数来源和完整性,不能说明交易当前处于什么状态。

所以,收到同步回调和订单支付成功是两件不同的事。

推荐处理流程

1. 对同步回调参数进行验签

先使用支付宝公钥验证 sign。如果验签失败,就不能继续信任任何回调参数。

验签通过后,还要检查:

  • app_id 是否属于当前应用;
  • seller_id 是否属于当前商户;
  • out_trade_no 是否存在,以及是否属于当前订单;
  • total_amount 是否与本地订单金额一致。

这些检查可以防止串单、金额不一致和配置错误,但仍不足以单独确认支付成功。

2. 查询支付宝交易状态

如果同步回调中没有 trade_status,可以使用 out_trade_no 或 trade_no 调用:

alipay.trade.query

判断支付结果时,应以查询响应中的 trade_status 为准。常见状态如下:

trade_status含义建议处理
WAIT_BUYER_PAY等待买家付款保持待支付
TRADE_SUCCESS支付成功可将订单更新为已支付
TRADE_FINISHED交易结束通常可按已支付处理,但应结合业务规则
TRADE_CLOSED交易关闭更新为已关闭或支付失败

只有查询接口调用成功,并且 trade_status 明确为 TRADE_SUCCESS,或为业务认可的 TRADE_FINISHED 时,才能执行支付成功后的业务逻辑。

3. 仍以异步通知作为主要入口

三种处理方式可以这样分工:

  • 同步回调:验签、查询订单状态并展示结果;
  • 异步通知:确认支付结果、更新订单并执行后续业务;
  • 主动查询:在异步通知延迟或缺失时补偿确认。

如果收到同步回调时,异步通知还没有处理完成,可以主动查询一次。若查询仍没有得到明确结果,页面应显示“支付结果确认中”,后续由异步通知或后台补单任务继续确认。

Java 示例

下面使用支付宝 Java SDK 展示核心处理逻辑。具体类名和构造方式应与项目实际使用的 SDK 版本一致。

public String handleReturn(Map<String, String> params) throws Exception {
    boolean signVerified = AlipaySignature.rsaCheckV1(
        params,
        ALIPAY_PUBLIC_KEY,
        params.getOrDefault("charset", "UTF-8"),
        params.getOrDefault("sign_type", "RSA2")
    );

    if (!signVerified) {
        return "回调验签失败";
    }

    String outTradeNo = params.get("out_trade_no");
    String totalAmount = params.get("total_amount");

    Order order = orderService.findByOutTradeNo(outTradeNo);
    if (order == null) {
        return "订单不存在";
    }

    if (!amountEquals(order.getTotalAmount(), totalAmount)) {
        return "订单金额不一致";
    }

    if (!EXPECTED_APP_ID.equals(params.get("app_id"))) {
        return "应用标识不一致";
    }

    if (!EXPECTED_SELLER_ID.equals(params.get("seller_id"))) {
        return "收款账号不一致";
    }

    AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
    request.setBizContent(
        "{\"out_trade_no\":\"" + escapeJson(outTradeNo) + "\"}"
    );

    AlipayTradeQueryResponse response = alipayClient.execute(request);

    if (!response.isSuccess()) {
        return "支付结果确认中";
    }

    String tradeStatus = response.getTradeStatus();

    if ("TRADE_SUCCESS".equals(tradeStatus)
            || "TRADE_FINISHED".equals(tradeStatus)) {
        orderService.markPaidIdempotently(
            outTradeNo,
            response.getTradeNo(),
            response.getTotalAmount()
        );
        return "支付成功";
    }

    if ("WAIT_BUYER_PAY".equals(tradeStatus)) {
        return "尚未完成支付";
    }

    if ("TRADE_CLOSED".equals(tradeStatus)) {
        return "交易已关闭";
    }

    return "支付结果确认中";
}

比较金额时应使用 BigDecimal,不要使用 double:

private boolean amountEquals(BigDecimal expected, String actual) {
    if (actual == null) {
        return false;
    }

    try {
        return expected.compareTo(new BigDecimal(actual)) == 0;
    } catch (NumberFormatException e) {
        return false;
    }
}

异步通知处理要点

异步通知也必须先验签,再检查订单号、应用、商户和金额。支付宝可能重复发送通知,因此订单更新必须保证幂等。

@Transactional
public void markPaidIdempotently(
        String outTradeNo,
        String alipayTradeNo,
        String totalAmount) {

    Order order = orderRepository.lockByOutTradeNo(outTradeNo);

    if (order == null) {
        throw new IllegalStateException("订单不存在");
    }

    if (order.isPaid()) {
        return;
    }

    if (order.getTotalAmount().compareTo(new BigDecimal(totalAmount)) != 0) {
        throw new IllegalStateException("订单金额不一致");
    }

    order.markPaid(alipayTradeNo);
    orderRepository.save(order);

    // 发货、充值等操作也需要具备幂等性
}

异步通知全部处理成功后,应按照支付宝接口要求返回成功响应。如果业务处理失败,不要提前返回成功,否则支付宝可能不会继续重试。

注意事项

  • 不能因为参数中有 trade_no 就认定订单已经支付;
  • 不能只检查同步回调是否验签成功;
  • 不能直接信任回调中的订单号和金额;
  • 支付状态确认前,不得发货、充值或开通服务;
  • 同步回调、异步通知和主动查询可能并发执行,因此订单更新必须幂等;
  • 建议设置定时补单机制,主动查询长时间处于“待支付”或“结果确认中”的订单;
  • 本地订单已经支付后,不能因重复通知再次发放权益;
  • 如果查询结果与本地状态冲突,应记录原始响应和交易号,并进入人工或自动对账流程。

简而言之,同步回调负责跳转和展示,异步通知及交易查询负责确认支付结果。

备注:内容仅供参考。