PAYATHON 2026

当面付返回支付宝交易号后无法唤起支付宝App

支付老李

结论

ap.tradePay 无法在普通手机浏览器中直接唤起支付宝 App。它依赖支付宝小程序或支付宝客户端提供的运行环境。即使服务端已经返回支付宝交易号 trade_no,在微信、Safari、Chrome 等普通浏览器中调用也不会生效。

具体处理方式要看支付入口:

  • 支付宝小程序内的页面:使用 ap.tradePay,传入 tradeNO。
  • 支付宝客户端 WebView 内的页面:等待 AlipayJSBridgeReady 事件触发,再调用 tradePay。
  • 普通浏览器内的页面:不要调用 ap.tradePay。应接入适用于浏览器的支付宝支付产品,或者展示当面付接口返回的二维码,让用户扫码支付。

原因

trade_no 只是支付宝交易流水号,本身不能唤起支付宝 App。ap.tradePay 是支付宝客户端环境注入的支付能力,普通浏览器没有对应的 JSAPI 上下文。

API 名称还区分大小写,正确写法是:

ap.tradePay

不能写成:

ap.tradepay

不过,即使大小写改对了,普通浏览器仍然无法调用,因为缺少所需的运行环境。

解决步骤

方案一:在支付宝小程序中支付

如果支付页面属于支付宝小程序,可以先由服务端创建交易,再把支付宝返回的交易号传给小程序:

ap.tradePay({
  tradeNO: '支付宝服务端返回的交易号'
}, (result) => {
  console.log('支付结果:', result);
});

调用前可以检查交易号和当前运行环境:

function pay(tradeNo) {
  if (!tradeNo) {
    console.error('缺少 tradeNO');
    return;
  }

  if (typeof ap === 'undefined' || typeof ap.tradePay !== 'function') {
    console.error('当前环境不支持 ap.tradePay');
    return;
  }

  ap.tradePay(
    {
      tradeNO: tradeNo
    },
    (result) => {
      console.log('客户端返回结果:', result);
    }
  );
}

这里的参数名是 tradeNO,不能写成 trade_no。

方案二:在支付宝客户端内的 H5 页面支付

如果页面是在支付宝客户端的内置 WebView 中打开,可以通过 AlipayJSBridge 发起支付。调用前需要等待桥接对象初始化完成:

<script>
  function tradePay(tradeNo) {
    AlipayJSBridge.call(
      'tradePay',
      {
        tradeNO: tradeNo
      },
      function (result) {
        console.log('支付结果:', result);
      }
    );
  }

  function startPay(tradeNo) {
    if (window.AlipayJSBridge) {
      tradePay(tradeNo);
      return;
    }

    document.addEventListener(
      'AlipayJSBridgeReady',
      function () {
        tradePay(tradeNo);
      },
      false
    );
  }
</script>

用户点击支付按钮后调用:

startPay('支付宝服务端返回的交易号');

如果页面不是在支付宝客户端中打开,AlipayJSBridgeReady 不会触发,这段代码也无法唤起支付宝。

方案三:普通浏览器使用当面付二维码

当面付主要用于扫码支付。如果服务端调用的是预创建接口,前端应该用接口返回的 qr_code 生成二维码,而不是在浏览器中调用 ap.tradePay。

可以把服务端返回的二维码内容交给前端二维码组件:

const qrCodeValue = response.qr_code;

// 将 qrCodeValue 交给二维码生成组件显示
new QRCode(document.getElementById('qrcode'), {
  text: qrCodeValue,
  width: 220,
  height: 220
});

用户使用支付宝扫描二维码并完成付款。之后,前端可以通过服务端轮询订单状态,也可以等待服务端收到支付宝异步通知后更新页面:

async function queryOrder(outTradeNo) {
  const response = await fetch(
    `/api/payment/status?outTradeNo=${encodeURIComponent(outTradeNo)}`
  );
  const result = await response.json();

  if (result.status === 'TRADE_SUCCESS') {
    console.log('支付成功');
    return;
  }

  setTimeout(() => queryOrder(outTradeNo), 2000);
}

轮询间隔和终止时间应按业务需求设置,不能无限轮询。

方案四:普通浏览器需要跳转支付

如果业务要求用户在手机浏览器中点击按钮,然后进入支付宝完成付款,服务端需要接入适用于 H5 浏览器场景的支付宝支付产品,并向前端返回相应的支付表单、跳转地址或支付参数。

不要把当面付接口返回的 trade_no 自行拼接成 URL Scheme,也不要依赖未经文档确认的支付宝唤起地址。能否直接跳转、需要哪些签约权限以及具体使用哪些接口参数,应以商户已签约的产品和当前支付宝开放平台文档为准。

服务端和前端应如何配合

可以按以下流程处理:

  1. 前端请求服务端创建订单,生成唯一的商户订单号 out_trade_no。
  2. 服务端根据实际支付场景调用对应的支付宝接口。
  3. 支付宝小程序或支付宝客户端内的页面使用 trade_no 调用客户端支付能力。
  4. 当面付扫码场景使用接口返回的 qr_code。
  5. 普通浏览器跳转场景使用对应 H5 支付产品返回的支付信息。
  6. 服务端接收支付宝异步通知,并主动查询订单状态进行校验。
  7. 前端负责展示支付结果,不能把客户端回调作为最终入账依据。

注意事项

  • ap.tradePay 中的 P 必须大写。
  • 请求参数通常写作 tradeNO,与服务端字段 trade_no 的命名不同。
  • 创建交易所用的接口必须和前端支付场景匹配,不能只凭一个 trade_no 在任意环境中发起支付。
  • 客户端回调可能表示取消、失败或状态未知,不能只根据回调页面判断支付成功。
  • 最终支付结果应由服务端结合异步通知和订单查询确认,同时校验商户订单号、金额、商户身份和交易状态。
  • 如果页面可能通过多种浏览器或客户端打开,应先识别运行环境,再提供对应的“小程序支付”“支付宝内支付”“扫码支付”或“H5 支付”入口。

备注:内容仅供参考。