电脑网站支付扫码后如何唤起支付宝 App 支付
结论
不能通过修改 alipay.trade.page.pay 返回的电脑网站支付页面,强制增加“支付宝支付”按钮并唤起支付宝 App。
应根据实际支付场景选择接口:
- 用户直接使用支付宝扫描二维码付款:使用
alipay.trade.precreate,将接口返回的qr_code生成二维码。 - 用户在手机浏览器中打开支付页,再点击按钮唤起支付宝 App:使用
alipay.trade.wap.pay。 - 用户在电脑浏览器中完成网页支付:继续使用
alipay.trade.page.pay。
不要把 alipay.trade.page.pay 返回的 HTML 表单或跳转地址自行转换成二维码。即使扫码后能够打开页面,它仍属于电脑网站支付链路,支付宝客户端是否展示唤起按钮不由商户页面控制。
原因
alipay.trade.page.pay 面向电脑浏览器,通常返回用于跳转支付宝收银台的 HTML 表单。收银台的页面结构、密码输入方式以及是否显示客户端唤起入口,均由支付宝控制,商户无法向其中插入按钮。
如果二维码的内容只是商户页面地址,支付宝扫码后打开的可能是内置浏览器页面,而不是扫码支付收银台。此时,即使页面运行在支付宝客户端中,也不代表使用了正确的扫码支付产品。
此外,不建议自行拼接 alipays:// 等 URL Scheme。此类方式可能受客户端版本、浏览器策略和平台安全限制影响,也不能替代正式支付接口。
方案一:使用预创建接口生成付款二维码
如果目标是让用户用支付宝扫码后直接进入支付宝付款流程,推荐调用:
alipay.trade.precreate
接口成功后会返回 qr_code。二维码必须根据这个字段生成,不要使用电脑网站支付接口返回的整段 HTML。
下面以支付宝 Java SDK 的常见调用形式为例。具体类名和参数应以项目正在使用的 SDK 版本及当前开放平台文档为准。
AlipayTradePrecreateRequest request =
new AlipayTradePrecreateRequest();
request.setNotifyUrl("https://example.com/alipay/notify");
request.setBizContent("""
{
"out_trade_no": "ORDER_202609090001",
"total_amount": "99.00",
"subject": "订单支付"
}
""");
AlipayTradePrecreateResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
String qrCode = response.getQrCode();
// 将 qrCode 原样生成二维码并展示给用户
System.out.println(qrCode);
} else {
System.err.println(response.getCode());
System.err.println(response.getSubCode());
System.err.println(response.getSubMsg());
}
用户用支付宝扫描该二维码后,支付宝会按照当时可用的客户端支付流程处理。付款界面的具体样式、按钮名称和身份验证方式由支付宝决定。
方案二:手机网页使用 WAP 支付
如果二维码需要先打开商户自己的手机页面,并在该页面中提供“支付宝支付”按钮,则按钮点击后应由服务端调用:
alipay.trade.wap.pay
典型流程如下:
- 电脑页面展示二维码,二维码内容为商户自己的移动端订单地址。
- 手机扫码后打开商户移动页面。
- 用户点击“支付宝支付”。
- 前端请求商户服务端创建 WAP 支付。
- 服务端调用
alipay.trade.wap.pay,返回支付宝提供的 HTML 表单。 - 浏览器提交该表单,进入支付宝收银台。
- 收银台根据手机环境决定是否提供支付宝 App 唤起能力。
前端按钮示例:
<button type="button" id="alipay-button">支付宝支付</button>
<script>
document.getElementById("alipay-button").addEventListener("click", async () => {
const response = await fetch("/api/payment/alipay/wap", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
orderId: "ORDER_202609090001"
})
});
if (!response.ok) {
throw new Error("创建支付宝支付失败");
}
const html = await response.text();
document.open();
document.write(html);
document.close();
});
</script>
服务端 Java 示例:
AlipayTradeWapPayRequest request =
new AlipayTradeWapPayRequest();
request.setReturnUrl("https://example.com/payment/result");
request.setNotifyUrl("https://example.com/alipay/notify");
request.setBizContent("""
{
"out_trade_no": "ORDER_202609090001",
"total_amount": "99.00",
"subject": "订单支付",
"product_code": "QUICK_WAP_WAY",
"quit_url": "https://example.com/order/ORDER_202609090001"
}
""");
String form = alipayClient.pageExecute(request).getBody();
// 将 form 作为 text/html 返回给手机浏览器
这里返回的是可自动提交的 HTML 表单,不能将其当作普通 URL 解析后再自行拼接跳转参数。
支付结果处理
无论采用扫码支付还是 WAP 支付,都不能仅凭前端返回页面判断付款成功。可靠流程应以支付宝异步通知为主:
- 接收
notify_url的 POST 通知。 - 使用支付宝 SDK 验证签名。
- 核对
app_id、out_trade_no、total_amount、收款方等关键字段。 - 确认交易状态符合业务要求。
- 以幂等方式更新订单。
- 成功处理后按支付宝要求返回成功响应。
前端结果页只能用于展示和主动查询订单状态,不能直接把订单标记为已支付。
注意事项
alipay.trade.page.pay、alipay.trade.wap.pay和alipay.trade.precreate对应不同产品场景,不能仅靠改变二维码内容互相替代。- 同一业务订单不要随意重复创建不同支付产品的交易。如果需要切换支付方式,应先设计好商户订单号和支付宝交易的对应关系。
- 不要在前端保存应用私钥,也不要由浏览器直接完成签名。签名和支付请求应在服务端生成。
- 不要抓取或修改支付宝收银台 HTML,也不要通过 JavaScript 自动填写密码。
- 是否能唤起支付宝 App,受手机系统、浏览器、支付宝客户端以及开放平台产品能力影响。商户只能接入正确的支付产品,不能保证所有环境都显示完全相同的按钮。
- 如果用户本来就是用支付宝客户端扫码,后续出现的密码或生物识别页面通常已经属于支付宝支付流程,不应再尝试二次唤起 App。
备注:内容仅供参考。
