PAYATHON 2026

手机网页支付跳转支付宝后不显示金额和支付界面

支付阿杰

结论

这种情况通常不是支付宝客户端“没有识别金额”,而是商户页面只唤起了支付宝,却没有正确提交手机网站支付请求。

手机网页支付需要通过支付宝的 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_WAY
  • out_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();

更稳妥的做法是让浏览器直接访问支付接口,使后端返回的自动提交页面成为当前页面。

排查方法

打开手机浏览器的远程调试工具,检查整个支付链路:

  1. 点击支付按钮后,是否请求了商户后端的支付接口。
  2. 后端返回的是否为完整 HTML 表单,而不是 JSON 或经过转义的字符串。
  3. 表单是否提交到了正确的支付宝网关。
  4. 请求参数中是否有 biz_content、sign、app_id 和 method=alipay.trade.wap.pay。
  5. biz_content 中的 total_amount、out_trade_no 和 product_code 是否正确。
  6. 浏览器、WebView 或 CSP 策略是否阻止了自动提交脚本的执行。
  7. 支付宝返回地址中是否包含明确的错误码或错误信息。

如果是在微信内置浏览器、某些 App WebView 或限制跳转的环境中测试,还要确认当前容器是否允许唤起支付宝。可以同时在系统浏览器中测试,以判断问题来自支付参数还是浏览器环境。

注意事项

  • 金额必须由服务端从订单数据中读取,并在创建支付请求前校验订单状态。
  • total_amount 建议使用十进制字符串,例如 "99.00",不要通过浮点运算拼接金额。
  • out_trade_no 必须唯一标识商户订单,重复使用可能造成交易状态混乱。
  • return_url 只负责用户支付后的页面跳转,不能单独作为支付成功的依据。
  • 最终支付结果应以 notify_url 收到的异步通知或主动查询结果为准,同时验证通知签名、订单号、金额和商户身份。
  • 沙箱环境与正式环境的网关、应用、密钥和账号不能混用。
  • 不要自行拼接支付宝客户端 Scheme 来代替 alipay.trade.wap.pay 流程。
  • 如果后端生成的表单完整,但仍然只打开支付宝首页,应记录实际提交参数和支付宝返回内容,重点检查签名、网关环境及浏览器跳转链路。

备注:内容仅供参考。