支付宝扫码打开H5页面收款应选择哪种支付产品?
结论
这种场景通常适合接入支付宝的手机网站支付(WAP 支付),对应接口是:
alipay.trade.wap.pay
用户虽然通过支付宝“扫一扫”进入页面,但二维码只是 H5 页面的入口,并不意味着业务属于“扫码支付”。支付产品应根据后续流程来判断:用户在手机浏览器或支付宝内置浏览器中打开商户 H5 页面,再跳转至支付宝收银台完成付款。这属于典型的手机网站支付场景。
如果希望在支付宝内置浏览器中直接唤起客户端支付组件,而不经过普通 WAP 收银台跳转,则可以进一步评估 JSAPI 支付。使用这种方案时,页面通常需要运行在支付宝客户端中,同时满足产品签约、域名配置和接口调用等条件。
推荐的实现流程
手机网站支付的标准流程如下:
- 商户生成收款 H5 页面的地址。
- 将该地址制作成二维码。
- 用户使用支付宝扫一扫打开商户 H5 页面。
- 用户点击“立即支付”。
- H5 页面请求商户服务端创建支付。
- 服务端调用
alipay.trade.wap.pay。 - 前端提交支付宝返回的跳转表单,进入支付宝收银台。
- 支付完成后,支付宝向商户的
notify_url发送异步通知。 - 商户验签并更新订单状态。
二维码中可以直接放置业务页面地址,例如:
https://pay.example.com/order/202609090001
不要把这个二维码入口当成支付宝“当面付”的付款码或扫码支付接口。只有当二维码本身承载支付宝交易链接,用户扫码后直接进入支付宝收银台时,才更接近当面付的扫码支付模式。
服务端调用示例
下面是支付宝 Java SDK 的常见调用方式。具体类名和配置方式可能随 SDK 版本变化,请以当前接入文档和实际使用的 SDK 为准。
AlipayClient alipayClient = new DefaultAlipayClient(
gatewayUrl,
appId,
merchantPrivateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2"
);
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.setOutTradeNo("202609090001");
model.setSubject("订单付款");
model.setTotalAmount("99.00");
model.setProductCode("QUICK_WAP_WAY");
model.setQuitUrl("https://pay.example.com/order/202609090001");
request.setBizModel(model);
request.setReturnUrl(
"https://pay.example.com/alipay/return"
);
request.setNotifyUrl(
"https://api.example.com/payment/alipay/notify"
);
AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);
if (response.isSuccess()) {
String paymentForm = response.getBody();
// 将 paymentForm 返回给浏览器,由页面提交并跳转到支付宝收银台
} else {
throw new RuntimeException(
"创建支付宝支付失败:" + response.getSubMsg()
);
}
pageExecute 通常会返回一段用于跳转至支付宝收银台的 HTML 表单。服务端可以直接输出这段表单,也可以先将它返回给前端,再由前端写入页面并提交。
如果由服务端直接返回 HTML,需要正确设置响应类型:
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(paymentForm);
支付结果处理
不要只根据 return_url 页面的跳转结果判断付款是否成功。
return_url 是用户支付后浏览器跳转的地址。用户可能在支付后关闭页面、遇到网络中断,或者重复访问该地址。因此,订单状态应以支付宝发送至 notify_url 的异步通知为准。
处理异步通知时,至少需要完成以下检查:
- 使用支付宝公钥验证签名。
- 检查
app_id是否属于当前应用。 - 检查
out_trade_no是否存在。 - 核对
total_amount是否与商户订单一致。 - 核对收款方身份信息。
- 判断
trade_status。 - 以幂等方式更新订单。
- 处理成功后返回纯文本
success。
常见的成功状态包括:
TRADE_SUCCESS
TRADE_FINISHED
实际业务中,还要根据退款能力和订单生命周期等要求,确定不同状态的处理方式。
什么情况下选择 JSAPI 支付
同时满足以下条件时,可以考虑使用支付宝 JSAPI 支付:
- 页面明确运行在支付宝客户端的 WebView 中;
- 希望通过页面脚本直接唤起支付宝支付组件;
- 已开通对应产品并完成必要配置;
- 服务端能够先创建支付宝交易;
- 页面能够调用
AlipayJSBridge。
常见的前端调用形式如下:
function invokeAlipay(tradeNo) {
AlipayJSBridge.call(
"tradePay",
{
tradeNO: tradeNo
},
function (result) {
console.log(result);
}
);
}
if (window.AlipayJSBridge) {
invokeAlipay(tradeNo);
} else {
document.addEventListener(
"AlipayJSBridgeReady",
function () {
invokeAlipay(tradeNo);
},
false
);
}
这里的 tradeNo 是支付宝交易号,通常由服务端通过相应的交易创建接口获取。前端回调可以用于改善页面交互,但最终支付结果仍要由服务端查询或通过异步通知确认。
如果页面还可能在微信、系统浏览器或其他应用中打开,手机网站支付通常兼容性更好。使用 JSAPI 支付时,则要检测当前是否处于支付宝客户端环境,并准备无法调用时的降级方案。
注意事项
- 支付宝扫一扫打开普通 H5 URL,不等于使用“当面付”。
- 支付宝接口应由商户服务端调用,私钥不能放在 H5 页面或 JavaScript 中。
out_trade_no必须由商户生成并保持唯一。- 金额必须由服务端根据订单计算,不能直接采用前端提交的金额。
notify_url必须是支付宝服务器可以访问的 HTTPS 地址,不能使用localhost或局域网地址。- 支付宝可能重复发送异步通知,因此订单更新必须保证幂等。
- 用户付款前,需要检查订单是否过期、是否已经支付,以及金额是否发生变化。
- 产品开通条件、接口权限和域名要求可能随支付宝开放平台规则调整。正式接入前,请以商户账号后台显示的可签约产品和当前官方文档为准。
如果需求只是“扫码进入收款 H5,再从页面跳转至支付宝付款”,应优先选择 alipay.trade.wap.pay 手机网站支付。只有明确需要在支付宝客户端内原生唤起支付组件时,再考虑 JSAPI 支付。
备注:内容仅供参考。
