手机网页支付跳转支付宝后不显示金额和支付界面
结论
这种情况通常不是支付宝客户端“没有识别金额”,而是商户页面只唤起了支付宝,却没有正确提交手机网站支付请求。
手机网页支付需要通过支付宝的 alipay.trade.wap.pay 接口创建交易,再由手机浏览器执行接口返回的自动提交表单。仅打开支付宝 App、拼接支付宝 Scheme,或者通过 Ajax 获取支付表单后不执行,都无法正常进入支付收银台。
常见原因
1. 只唤起支付宝,没有创建交易
如果页面只执行支付宝 Scheme 跳转,支付宝虽然会打开,但无法获得具体的订单、金额和收款方信息,因此不会进入支付收银台。
支付宝 App 不会从前端页面读取支付金额。金额需要写入经过签名的支付请求,例如:
{
"out_trade_no": "ORDER_202609090001",
"total_amount": "99.00",
"subject": "订单支付",
"product_code": "QUICK_WAP_WAY"
}
2. 没有执行支付宝返回的表单
支付宝服务端 SDK 生成的结果通常是一段包含 <form> 和自动提交脚本的 HTML。如果后端将它包装成 JSON,或者前端只把它当作普通字符串处理,表单就不会提交。
下面这种调用方式经常引发问题:
fetch("/pay/create")
.then(response => response.json())
.then(data => {
window.location.href = data.url;
});
alipay.trade.wap.pay 的返回结果不一定是可以直接跳转的 URL。使用官方 SDK 时,通常需要把 pageExecute 生成的完整 HTML 交给浏览器执行。
3. 支付参数不完整或签名配置错误
需要检查以下内容:
product_code是否为QUICK_WAP_WAYout_trade_no是否唯一total_amount是否为合法的金额字符串subject是否非空app_id、应用私钥和支付宝公钥是否匹配- 网关、应用环境和密钥是否属于同一环境
charset、sign_type是否与签名配置一致
请求未通过支付宝校验时,通常还会出现错误页面或错误码。如果页面只是打开了支付宝 App 首页,应先检查跳转方式和表单提交过程。
推荐解决步骤
第一步:由服务端创建支付请求
订单号、金额和商品名称应由服务端根据真实订单生成,不要直接信任前端提交的金额。
下面是使用 Java 支付宝 SDK 的示例。具体构造方法可能因 SDK 版本而略有不同,应以项目实际依赖提供的 API 为准。
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do",
APP_ID,
APP_PRIVATE_KEY,
"json",
"UTF-8",
ALIPAY_PUBLIC_KEY,
"RSA2"
);
AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
request.setReturnUrl("https://www.example.com/pay/return");
request.setNotifyUrl("https://www.example.com/pay/notify");
AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.setOutTradeNo("ORDER_202609090001");
model.setTotalAmount("99.00");
model.setSubject("订单支付");
model.setProductCode("QUICK_WAP_WAY");
request.setBizModel(model);
String paymentForm = alipayClient.pageExecute(request).getBody();
第二步:把支付表单直接返回给手机浏览器
接口响应需要使用 HTML 内容类型,并将 paymentForm 原样写入响应体:
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(paymentForm);
response.getWriter().flush();
不要再对表单进行 JSON 序列化。下面的处理可能会把 HTML 变成普通字符串,导致自动提交脚本无法执行:
// 不推荐
return Result.success(paymentForm);
第三步:通过正常的页面跳转发起支付
前端可以提交表单,或者通过页面导航访问后端支付接口:
<form action="/pay/create" method="post">
<input type="hidden" name="orderNo" value="ORDER_202609090001">
<button type="submit">支付宝支付</button>
</form>
也可以在用户点击支付按钮后跳转:
window.location.href = "/pay/create?orderNo=ORDER_202609090001";
后端收到 orderNo 后查询订单,再生成支付宝支付表单。不要将 URL 中的金额参数直接作为可信数据传给支付接口。
如果业务必须通过 Ajax 获取表单,也可以将表单写入页面并执行,但这种方式的兼容性通常不如直接跳转:
const response = await fetch("/pay/create", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: new URLSearchParams({
orderNo: "ORDER_202609090001"
})
});
const paymentForm = await response.text();
document.open();
document.write(paymentForm);
document.close();
更稳妥的做法是让浏览器直接访问支付接口,使后端返回的自动提交页面成为当前页面。
排查方法
打开手机浏览器的远程调试工具,检查整个支付链路:
- 点击支付按钮后,是否请求了商户后端的支付接口。
- 后端返回的是否为完整 HTML 表单,而不是 JSON 或经过转义的字符串。
- 表单是否提交到了正确的支付宝网关。
- 请求参数中是否有
biz_content、sign、app_id和method=alipay.trade.wap.pay。 biz_content中的total_amount、out_trade_no和product_code是否正确。- 浏览器、WebView 或 CSP 策略是否阻止了自动提交脚本的执行。
- 支付宝返回地址中是否包含明确的错误码或错误信息。
如果是在微信内置浏览器、某些 App WebView 或限制跳转的环境中测试,还要确认当前容器是否允许唤起支付宝。可以同时在系统浏览器中测试,以判断问题来自支付参数还是浏览器环境。
注意事项
- 金额必须由服务端从订单数据中读取,并在创建支付请求前校验订单状态。
total_amount建议使用十进制字符串,例如"99.00",不要通过浮点运算拼接金额。out_trade_no必须唯一标识商户订单,重复使用可能造成交易状态混乱。return_url只负责用户支付后的页面跳转,不能单独作为支付成功的依据。- 最终支付结果应以
notify_url收到的异步通知或主动查询结果为准,同时验证通知签名、订单号、金额和商户身份。 - 沙箱环境与正式环境的网关、应用、密钥和账号不能混用。
- 不要自行拼接支付宝客户端 Scheme 来代替
alipay.trade.wap.pay流程。 - 如果后端生成的表单完整,但仍然只打开支付宝首页,应记录实际提交参数和支付宝返回内容,重点检查签名、网关环境及浏览器跳转链路。
备注:内容仅供参考。
