PAYATHON 2026

支付宝 JSSDK ap.tradePay 文档及支付结果查询

支付老李

结论

ap.tradePay 的作用是在支付宝客户端内唤起收银台,它不会提供最终且可信的支付状态。前端回调可以用于更新页面交互,但不能作为发货、记账或开通服务的依据。

商户服务端应通过以下方式确认支付结果:

  1. 接收支付宝异步通知并完成验签。
  2. 调用 alipay.trade.query 主动查询订单。
  3. 查询结果为 TRADE_SUCCESS 或 TRADE_FINISHED 时,才能按支付成功处理。

使用 ap.tradePay 通常不代表必须申请生活号。接入支付真正需要的是支付宝开放平台应用、对应的支付产品权限,以及符合产品要求的签约和授权配置。只有当业务页面必须从生活号进入,或者所选支付产品明确要求生活号时,才需要申请生活号。具体准入条件以支付宝开放平台控制台当前显示的产品要求为准。

官方文档应该看哪些部分

参考页面中的 ap.tradePay 文档主要说明客户端如何调用接口,所以内容相对简单。完整的支付流程通常分布在以下几类文档中:

  • 支付宝 JSAPI 的 ap.tradePay 接口说明;
  • 所用支付产品的接入文档;
  • 交易创建接口文档,例如适用场景下的 alipay.trade.create;
  • alipay.trade.query 统一收单线下交易查询接口文档;
  • 支付结果异步通知及 RSA2 验签文档。

接入前应先确认商户签约了哪一种支付产品。不同产品使用的订单创建接口、必填参数和准入条件可能不同,不能仅凭 ap.tradePay 页面推断整套支付流程。

推荐的支付流程

可以按下面的流程接入:

  1. 浏览器请求商户服务端创建订单。
  2. 商户服务端生成唯一的 out_trade_no,再根据已签约的产品调用支付宝交易创建接口。
  3. 服务端将支付宝返回的 trade_no 传给前端。
  4. 前端调用 ap.tradePay 唤起收银台。
  5. 收银台关闭后,前端请求商户服务端查询订单状态。
  6. 服务端调用 alipay.trade.query,或者读取已经验签并写入数据库的异步通知结果。
  7. 服务端统一处理业务状态,再将结果返回前端。

不要在浏览器中直接调用支付宝 OpenAPI。应用私钥、签名过程和订单金额都必须保留在服务端。

前端调用示例

async function pay(orderId) {
  // tradeNO 应由商户服务端创建交易后返回
  const createResponse = await fetch('/api/payment/create', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ orderId })
  });

  const order = await createResponse.json();

  ap.tradePay(
    {
      tradeNO: order.tradeNo
    },
    function (result) {
      // 该回调只能表示收银台本次交互结果,不能直接触发发货
      console.log('tradePay result:', result);

      pollPaymentStatus(order.orderNo);
    }
  );
}

async function pollPaymentStatus(orderNo) {
  const maximumAttempts = 10;

  for (let attempt = 0; attempt < maximumAttempts; attempt += 1) {
    const response = await fetch(
      `/api/payment/status?orderNo=${encodeURIComponent(orderNo)}`
    );
    const result = await response.json();

    if (result.status === 'PAID') {
      showPaymentSuccess();
      return;
    }

    if (result.status === 'CLOSED' || result.status === 'FAILED') {
      showPaymentFailure();
      return;
    }

    await new Promise(resolve => setTimeout(resolve, 2000));
  }

  showPaymentProcessing();
}

ap.tradePay 回调中的 resultCode 常用于区分成功返回、处理中、用户取消和调用失败等结果。但网络中断、页面关闭等情况都可能影响客户端返回值,具体码值应以当前版本的官方 JSAPI 文档为准。即使客户端返回成功,仍需由服务端再次确认。

服务端查询示例

下面使用支付宝 Java SDK 的常见写法说明查询逻辑。实际类名和初始化参数应与项目使用的 SDK 版本一致。

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

AlipayTradeQueryResponse response = alipayClient.execute(request);

if (!response.isSuccess()) {
    // 这里表示查询接口调用失败,不应直接判定用户未付款
    return PaymentStatus.UNKNOWN;
}

String tradeStatus = response.getTradeStatus();

if ("TRADE_SUCCESS".equals(tradeStatus)
        || "TRADE_FINISHED".equals(tradeStatus)) {
    return PaymentStatus.PAID;
}

if ("TRADE_CLOSED".equals(tradeStatus)) {
    return PaymentStatus.CLOSED;
}

if ("WAIT_BUYER_PAY".equals(tradeStatus)) {
    return PaymentStatus.PENDING;
}

return PaymentStatus.UNKNOWN;

各交易状态通常可以这样理解:

  • WAIT_BUYER_PAY:交易已创建,正在等待付款;
  • TRADE_SUCCESS:支付成功;
  • TRADE_FINISHED:交易已完成,通常不能再退款;
  • TRADE_CLOSED:交易已关闭。

如果查询接口暂时失败或没有查到订单,不要立即将业务订单改为支付失败。网络延迟、异步通知延迟,以及交易刚创建但尚未完成同步,都可能造成短时间内无法取得最终结果。

异步通知也必须校验

收到支付宝异步通知后,应先验签,再更新订单。除签名外,还要核对以下内容:

  • app_id 是否属于当前应用;
  • seller_id 是否属于当前收款商户;
  • out_trade_no 是否存在,并且对应当前业务订单;
  • total_amount 是否与订单应付金额一致;
  • 币种、交易状态等字段是否符合预期;
  • 订单是否已经处理,防止重复发货。

通知处理必须具备幂等性。所有校验均通过且结果成功写入数据库后,通知接口才能返回支付宝要求的成功响应。请求中即使包含 trade_status=TRADE_SUCCESS,也不能直接认定支付成功。

是否必须申请生活号

生活号和开放平台应用不是同一个概念:

  • 生活号用于触达用户和运营内容;
  • 开放平台应用负责承载接口权限、密钥、网关调用和产品签约;
  • ap.tradePay 是支付宝客户端内提供的 JSAPI 调用能力。

因此,仅仅使用 ap.tradePay,通常无法得出必须申请生活号的结论。页面也可以通过其他合规入口在支付宝客户端内打开。如果业务依赖生活号菜单、生活号用户体系,或者当前签约产品将生活号列为准入条件,则仍需申请并配置生活号。

正式接入前,应在支付宝开放平台控制台核实:

  1. 当前应用类型是否支持目标支付产品;
  2. 商户是否已经签约并开通相关能力;
  3. 应用是否已经配置公钥、回调地址和授权信息;
  4. 页面是否运行在支持 ap.tradePay 的支付宝客户端环境中;
  5. 当前产品是否要求使用生活号、小程序或其他特定载体。

最终应以所签约支付产品的最新准入规则和控制台审核结果为准,不能只根据 ap.tradePay 的 JSAPI 页面作出判断。

备注:内容仅供参考。