当面付返回支付宝交易号后无法唤起支付宝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,也不要依赖未经文档确认的支付宝唤起地址。能否直接跳转、需要哪些签约权限以及具体使用哪些接口参数,应以商户已签约的产品和当前支付宝开放平台文档为准。
服务端和前端应如何配合
可以按以下流程处理:
- 前端请求服务端创建订单,生成唯一的商户订单号
out_trade_no。 - 服务端根据实际支付场景调用对应的支付宝接口。
- 支付宝小程序或支付宝客户端内的页面使用
trade_no调用客户端支付能力。 - 当面付扫码场景使用接口返回的
qr_code。 - 普通浏览器跳转场景使用对应 H5 支付产品返回的支付信息。
- 服务端接收支付宝异步通知,并主动查询订单状态进行校验。
- 前端负责展示支付结果,不能把客户端回调作为最终入账依据。
注意事项
ap.tradePay中的P必须大写。- 请求参数通常写作
tradeNO,与服务端字段trade_no的命名不同。 - 创建交易所用的接口必须和前端支付场景匹配,不能只凭一个
trade_no在任意环境中发起支付。 - 客户端回调可能表示取消、失败或状态未知,不能只根据回调页面判断支付成功。
- 最终支付结果应由服务端结合异步通知和订单查询确认,同时校验商户订单号、金额、商户身份和交易状态。
- 如果页面可能通过多种浏览器或客户端打开,应先识别运行环境,再提供对应的“小程序支付”“支付宝内支付”“扫码支付”或“H5 支付”入口。
备注:内容仅供参考。
