PAYATHON 2026

支付宝沙箱手机网站支付无法拉起并返回 404 Not Found

支付老李

结论

仅凭这个 404 页面,还不能认定支付宝沙箱服务异常。

错误出现在支付宝沙箱的内部 H5 落地页:

mobileclientgw-sandbox.dl.alipaydev.com/h5pay/landing/index.html

不过,请求中有一项信息明显异常:

referer=https%3A%2F%2F%2F

解码后是:

https:///

这不是合法的来源地址。通常是商户侧的域名、return_url、跳转地址或 URL 拼接配置为空、缺少主机名,也可能是错误地进行了二次编码。这类参数异常会影响支付宝内部路由生成或定位收银台页面,最终可能返回 404。

建议先检查支付请求的生成过程,不要直接访问或自行拼接报错页面中的 h5pay/landing/index.html 地址。

建议的排查顺序

1. 确认使用的是沙箱网关

手机网站支付请求应提交到沙箱开放平台网关:

https://openapi.alipaydev.com/gateway.do

不要混用正式环境网关、正式应用 ID、正式密钥和沙箱配置。以下配置必须来自同一套沙箱应用:

  • app_id
  • 应用私钥
  • 支付宝公钥
  • 网关地址
  • 签名方式

报错 URL 中的 targetDispatchSystem=unitradeprod 是支付宝内部路由参数。不能仅凭其中的 prod,就判断商户请求进入了正式环境。

2. 检查 return_url 和站点域名

先检查最终传给 SDK 的 return_url。它必须是完整、合法的绝对 URL,例如:

https://example.com/alipay/return

以下写法都可能引发问题:

https:///
https://
/alipay/return
example.com/alipay/return

如果地址通过环境变量拼接生成,需要确认域名变量不是空字符串。例如:

String returnUrl = siteBaseUrl + "/alipay/return";

当 siteBaseUrl 为空或只有 https:// 时,拼接出来的地址就是无效的。

反向代理配置也需要检查。应用部署在 Nginx、网关或负载均衡器之后时,如果程序通过请求对象自动获取域名,可能无法取得正确的 Host 或协议。更稳妥的做法是用配置项保存完整的外部访问地址,不要临时根据当前请求推导支付回跳域名。

3. 不要自行拼接支付宝内部落地页

下面的地址是支付宝处理支付请求后生成的临时页面:

/h5pay/landing/index.html?h5_request_token=...

其中的 h5_request_token 通常具有时效性,还可能与当前会话、请求参数或生成时间有关。请勿:

  • 手工拼接该 URL;
  • 保存后重复使用;
  • 修改其中的查询参数;
  • 对整个 URL 再做一次 URL 编码;
  • 将旧请求中的 token 用于新订单。

商户程序应调用 alipay.trade.wap.pay,再将支付宝 SDK 返回的 HTML 表单原样输出给浏览器。

Java 调用示例

下面省略了具体的 SDK 版本,类名和调用方式采用支付宝 Java SDK 的常见接口:

AlipayClient alipayClient = new DefaultAlipayClient(
    "https://openapi.alipaydev.com/gateway.do",
    sandboxAppId,
    merchantPrivateKey,
    "json",
    "UTF-8",
    alipayPublicKey,
    "RSA2"
);

AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();

request.setReturnUrl("https://example.com/alipay/return");
request.setNotifyUrl("https://example.com/alipay/notify");

AlipayTradeWapPayModel model = new AlipayTradeWapPayModel();
model.setOutTradeNo("ORDER_20240524_001");
model.setTotalAmount("0.01");
model.setSubject("沙箱支付测试");
model.setProductCode("QUICK_WAP_WAY");
model.setQuitUrl("https://example.com/order");

request.setBizModel(model);

AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);

if (response.isSuccess()) {
    String formHtml = response.getBody();

    // Web 框架中应以 text/html 返回,且不要转义表单内容。
    httpServletResponse.setContentType("text/html;charset=UTF-8");
    httpServletResponse.getWriter().write(formHtml);
    httpServletResponse.getWriter().flush();
} else {
    throw new IllegalStateException(
        "支付宝请求失败,code=" + response.getCode()
            + ", subCode=" + response.getSubCode()
            + ", msg=" + response.getMsg()
            + ", subMsg=" + response.getSubMsg()
    );
}

其中需要特别确认的参数是:

model.setProductCode("QUICK_WAP_WAY");

还要确保订单号唯一、金额格式正确,并记录支付宝 SDK 返回的 code、sub_code、msg、sub_msg 和请求 ID,以便排查问题。

检查返回 HTML 的处理方式

pageExecute() 通常返回一段自动提交的 HTML 表单。服务端必须将它作为 HTML 返回,不能包装成 JSON:

{
  "html": "<form name=\"punchout_form\" ...>"
}

也不能先转义 HTML,再将其直接展示出来:

&lt;form name="punchout_form"&gt;

如果前端通过 AJAX 获取表单,再用 innerHTML 注入页面,浏览器通常不会自动执行其中的 <script>,表单也可能无法提交。更简单可靠的做法是让浏览器直接访问服务端的支付发起接口,由该接口输出支付宝返回的完整 HTML。

例如:

window.location.href = "/payment/alipay/wap?orderNo=ORDER_20240524_001";

检查 URL 编码

return_url、notify_url 和业务参数应统一交给 SDK 签名和编码,不要预先对参数整体多次执行 URLEncoder.encode()。

尤其要避免下面的写法:

String encodedReturnUrl =
    URLEncoder.encode(
        URLEncoder.encode(returnUrl, StandardCharsets.UTF_8),
        StandardCharsets.UTF_8
    );

重复编码会将:

https://example.com/alipay/return

逐步转换成包含 %25 的字符串,进而造成验签、跳转或内部解析异常。

报错地址的 query_params 中出现 %252F、%253D,并不一定说明商户侧进行了重复编码,因为支付宝内部也可能再次封装参数。判断是否存在编码问题,应以商户提交到开放平台网关的原始请求为准。

检查浏览器和网络环境

完成参数检查后,可以按以下方式交叉测试:

  1. 使用手机系统浏览器直接打开支付发起接口。
  2. 分别在 Wi-Fi 和移动网络下测试。
  3. 清除浏览器缓存并重新创建订单。
  4. 不要重复打开已经生成的收银台 URL。
  5. 如果当前使用 App WebView 测试,改用系统浏览器验证。
  6. 检查代理、抓包软件、公司网络网关或 DNS 是否改写了请求。
  7. 确认设备时间正常,以免临时令牌或签名因时间偏差失效。

如果系统浏览器能够正常拉起支付页面,而 App 内的 WebView 不行,问题通常出在 WebView 的跳转策略、外部协议处理、Cookie、User-Agent 或重定向限制上,不应直接归因于支付宝沙箱整体故障。

如何判断是否为沙箱侧异常

以下条件全部满足后,才有较充分的理由怀疑支付宝沙箱出现了临时故障:

  • 沙箱网关、应用 ID 和密钥配置正确;
  • return_url、notify_url、quit_url 都是合法地址;
  • 使用 SDK 直接调用 alipay.trade.wap.pay;
  • 没有自行拼接或重复编码支付宝地址;
  • 每次测试都会创建新订单,并重新生成支付表单;
  • 多个浏览器、设备和网络都能稳定复现;
  • 同一套业务代码切换到其他确认可用的测试配置后,表现不同;
  • SDK 请求成功,但支付宝生成的落地页持续返回同类 404。

这时可以保存以下信息,并提交给支付宝技术支持:

  • 沙箱应用 app_id;
  • 接口名称 alipay.trade.wap.pay;
  • out_trade_no;
  • 完整的错误时间和时区;
  • SDK 返回的响应码、子响应码及请求 ID;
  • 脱敏后的网关请求参数;
  • 404 页面中的 Server、Date 和 URL;
  • 复现步骤及所用的浏览器环境。

不要在工单、日志或截图中公开商户私钥、完整签名、用户敏感信息或可重复使用的支付令牌。

根据当前错误信息,最需要先处理的是异常的 referer=https:///。检查站点基础 URL、return_url 的生成逻辑和代理转发配置后,重新创建订单,再通过 SDK 生成新的支付表单。这样比反复访问现有的 404 地址更有助于定位问题。

备注:内容仅供参考。