PAYATHON 2026

浏览器H5页面唤起支付宝收银台JSAPI无反应

支付阿杰

结论

普通手机浏览器里的 H5 页面无法直接调用支付宝客户端的 AlipayJSBridge 收银台 JSAPI。这个 JSAPI 依赖支付宝 App 内置的 WebView 环境。在微信、Chrome、Safari 或系统浏览器中,页面通常拿不到 AlipayJSBridge,点击支付后就可能没有反应。

需要根据页面的运行环境选择支付方式:

  • 在支付宝 App 内打开页面:等待 AlipayJSBridge 就绪,再调用 tradePay。
  • 在普通浏览器中打开页面:使用支付宝手机网站支付接口 alipay.trade.wap.pay,由服务端生成签名后的支付表单或跳转内容。
  • 在微信内置浏览器中打开页面:还要处理微信对支付宝支付页面的限制,通常需要提示用户改用系统浏览器打开。

为什么调用后没有反应

当前环境没有支付宝 JSBridge

AlipayJSBridge 不是浏览器的标准 API,而是支付宝客户端注入页面的桥接对象。在普通浏览器中执行下面的代码时,这个对象通常不存在:

AlipayJSBridge.call('tradePay', {
  tradeNO: '支付宝交易号'
});

可以先检查:

console.log(window.AlipayJSBridge);

如果输出为 undefined,说明当前页面不具备调用该 JSAPI 的条件。

调用时机过早

即使页面是在支付宝客户端中打开的,JSBridge 也可能还没有完成注入。如果页面一加载就立即调用,可能没有响应,也可能直接报错。此时需要监听 AlipayJSBridgeReady。

传入了错误的订单标识

tradePay 要求的 tradeNO 一般是支付宝创建交易后返回的交易号,不是商户自己的 out_trade_no。

如果服务端只生成了商户订单号,没有通过相应接口取得支付宝交易号,就不能把 out_trade_no 直接作为 tradeNO 传入。具体使用哪个字段,应以当前接入的支付产品和接口返回值为准。

支付请求没有通过用户操作触发

浏览器可能会拦截不是由用户主动触发的跳转、弹窗或表单提交。例如,在异步回调或定时器中调用 window.open(),可能会被浏览器当作弹窗拦截。

浏览器 H5 支付应优先在当前页面提交支付表单,不要依赖异步弹窗。

支付宝客户端内的正确调用方式

如果业务确定运行在支付宝 App 内,可以等 JSBridge 就绪后再调用:

function ready(callback) {
  if (window.AlipayJSBridge) {
    callback();
    return;
  }

  document.addEventListener(
    'AlipayJSBridgeReady',
    callback,
    false
  );
}

function openAlipayCashier(tradeNo) {
  ready(function () {
    AlipayJSBridge.call(
      'tradePay',
      {
        tradeNO: tradeNo
      },
      function (result) {
        console.log('tradePay result:', result);

        // 此处结果只能用于页面提示。
        // 最终支付状态应由服务端查询或异步通知确认。
      }
    );
  });
}

调用前最好先检查运行环境:

function isAlipayClient() {
  return /AlipayClient/i.test(navigator.userAgent);
}

if (!isAlipayClient()) {
  console.warn('当前页面不在支付宝客户端内,不能直接使用收银台 JSAPI');
}

User-Agent 只能用来给出前端提示或分流支付流程,不能作为安全校验条件。

普通浏览器应使用手机网站支付

普通浏览器中的标准支付流程如下:

  1. 前端请求业务服务端创建支付。
  2. 服务端创建业务订单。
  3. 服务端调用 alipay.trade.wap.pay,组装参数并完成签名。
  4. 服务端把支付宝 SDK 生成的 HTML 表单返回给前端。
  5. 前端将表单写入页面并自动提交,进入支付宝支付流程。

前端示例:

async function startWapPay(orderId) {
  const response = await fetch('/api/pay/alipay/wap', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    credentials: 'include',
    body: JSON.stringify({
      orderId
    })
  });

  if (!response.ok) {
    throw new Error(`创建支付失败:HTTP ${response.status}`);
  }

  const html = await response.text();

  // html 应由受信任的业务服务端返回,
  // 内容通常是支付宝 SDK 生成的自动提交表单。
  document.open();
  document.write(html);
  document.close();
}

服务端请求中的业务参数通常类似:

{
  "out_trade_no": "ORDER_202609080001",
  "total_amount": "99.00",
  "subject": "订单支付",
  "product_code": "QUICK_WAP_WAY",
  "quit_url": "https://www.example.com/order",
  "return_url": "https://www.example.com/pay/result"
}

这只是参数结构示例。实际必填项、网关地址、签名算法和 SDK 调用方式,应以当前支付宝开放平台文档以及所用服务端 SDK 的说明为准。

支付签名必须由服务端完成。不要把应用私钥、签名逻辑或可任意修改的支付金额放到浏览器中。

建议按以下顺序排查

1. 确认页面到底运行在哪里

在控制台输出:

console.log(navigator.userAgent);
console.log('AlipayJSBridge:', window.AlipayJSBridge);

如果页面位于普通浏览器,并且 AlipayJSBridge 为 undefined,就不必继续排查 JSAPI 参数了,应直接改用 alipay.trade.wap.pay。

2. 检查点击事件是否真正执行

document.querySelector('#payButton').addEventListener('click', function () {
  console.log('pay button clicked');
});

同时查看控制台中是否出现以下错误:

AlipayJSBridge is not defined

或者:

Cannot read properties of undefined

如果业务代码捕获异常后没有记录日志,用户看到的现象就是“点击没反应”。

3. 检查创建订单接口

先确认服务端返回的内容属于哪一种:

  • 商户订单号 out_trade_no
  • 支付宝交易号 trade_no
  • WAP 支付表单
  • 支付跳转地址
  • SDK 返回的支付参数

不同支付产品的返回内容不能混用,尤其不能把商户订单号直接填入要求支付宝交易号的 tradeNO 字段。

4. 检查域名和回跳地址

确认以下地址能够从公网访问,并且使用完整 URL:

  • return_url
  • notify_url
  • quit_url

如果使用 HTTPS,还要确认网站证书有效,页面没有被混合内容策略拦截,CSP 也没有阻止表单提交或页面跳转。

5. 检查内置浏览器限制

如果页面位于微信或其他 App 的内置浏览器中,即使用的是 WAP 支付,也可能因为客户端策略而无法正常跳转到支付宝。

这时应向用户给出明确提示,例如:

function isWeChat() {
  return /MicroMessenger/i.test(navigator.userAgent);
}

if (isWeChat()) {
  alert('请点击右上角,选择“在浏览器打开”后继续支付');
}

6. 以服务端结果确认支付状态

前端回调、同步跳转和 JSAPI 返回值都不能单独作为发货依据。可靠的处理流程是:

  1. 接收支付宝异步通知并验签。
  2. 校验应用、商户订单号、金额和交易状态。
  3. 以幂等方式更新订单。
  4. 必要时由服务端主动查询交易状态。

用户从收银台返回页面后,前端可以轮询业务系统自己的订单查询接口,但不能直接相信 URL 参数或前端回调。

最容易踩的几个坑

  • 在 Chrome、Safari 等普通浏览器中直接调用 AlipayJSBridge。
  • 没有等待 AlipayJSBridgeReady 就执行 tradePay。
  • 混淆 tradeNO、trade_no 和 out_trade_no。
  • 在前端生成签名或暴露应用私钥。
  • 把同步回跳页面当成支付成功的凭据。
  • 在微信内置浏览器中测试,却误以为支付宝接口没有响应。
  • 异常被空的 catch 吞掉,页面既不报错,也不给用户提示。
  • 用户重复点击支付按钮,造成重复创建订单或多个支付请求同时执行。

排查时先确认页面运行在哪个容器中。只有支付宝客户端内的页面才能使用收银台 JSAPI;面向普通浏览器的 H5 页面应接入 alipay.trade.wap.pay。多数“调用无反应”的问题都出在这里。

备注:内容仅供参考。