PAYATHON 2026

沙箱环境下 PC 支付正常但 H5 支付提示订单信息异常

支付阿杰

结论

PC 支付正常,不等于同一套业务参数可以直接用于 H5 支付。两者通常使用不同的 API,product_code、请求对象和页面跳转方式也有区别。

H5 出现“订单信息异常,请联系卖家”时,先检查以下几项:

  1. H5 是否调用了 alipay.trade.wap.pay。
  2. product_code 是否为 QUICK_WAP_WAY。
  3. 是否重复使用了已经通过 PC 支付接口创建过的 out_trade_no。
  4. 沙箱 app_id、网关、密钥和应用产品权限是否来自同一套环境。
  5. 服务端是否正确返回并输出支付宝生成的跳转表单,而非将响应作为普通 JSON 处理。

PC 支付和 H5 支付不能共用完整参数

PC 网站支付通常调用:

alipay.trade.page.pay

常用产品码为:

FAST_INSTANT_TRADE_PAY

H5 手机网站支付通常调用:

alipay.trade.wap.pay

对应的产品码为:

QUICK_WAP_WAY

订单号、金额和标题等业务数据可以复用,但完整的 biz_content 不能原样照搬,PC 支付的 API 名称和产品码也不能继续用于 H5 支付。

H5 支付的业务参数可以按以下结构构造:

{
  "out_trade_no": "ORDER_202609150001",
  "total_amount": "0.01",
  "subject": "测试订单",
  "product_code": "QUICK_WAP_WAY",
  "quit_url": "https://example.com/order/ORDER_202609150001"
}

金额建议使用字符串传递,单位为元,并确保小数位与订单系统中的实际金额一致。

推荐排查步骤

1. 确认调用的是 H5 支付接口

如果移动端仍调用 alipay.trade.page.pay,只是将 PC 页面放入手机浏览器或 WebView,可能出现页面兼容、产品类型或订单校验异常。

H5 支付应明确使用:

method=alipay.trade.wap.pay

同时确认:

product_code=QUICK_WAP_WAY

H5 请求中不要继续传:

product_code=FAST_INSTANT_TRADE_PAY

2. 使用全新的商户订单号测试

out_trade_no 是商户订单号,在同一应用和商户范围内通常必须保持唯一。

如果先用某个订单号发起 PC 支付,再用相同订单号发起 H5 支付,支付宝侧可能已经存在该订单。一旦接口、金额、标题或产品类型发生变化,就可能触发重复订单或订单信息不一致。

排查时不要只修改时间戳或请求签名,直接生成新的订单号:

PC_TEST_202609150001
WAP_TEST_202609150001

如果更换订单号后可以正常支付,问题很可能与旧订单状态或订单号复用有关。

3. 核对沙箱配置是否一致

沙箱请求需要使用对应沙箱应用的完整配置,包括:

app_id
merchant_private_key
alipay_public_key
gateway

常见的沙箱网关为:

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

以下配置不能混用:

  • 沙箱 app_id 与正式环境网关
  • 正式环境应用私钥与沙箱应用公钥
  • 应用公钥与支付宝公钥
  • 不同沙箱应用的密钥
  • 重新生成的应用密钥与旧支付宝公钥

PC 支付已经正常,说明公共参数和签名配置出错的可能性相对较低。不过,仍要确认 H5 代码是否单独创建了另一套客户端配置。

4. 检查沙箱应用的产品能力

PC 网站支付和手机网站支付是两项不同的支付能力。需要进入开放平台的沙箱应用,确认手机网站支付是否可用,以及当前应用是否具备对应的产品能力。

沙箱控制台的入口和页面展示可能随平台调整,应以当前沙箱应用页面中的信息为准。如果接口和参数都正确,但所有 H5 订单仍在支付宝收银台被拒绝,就需要重点检查这一项。

5. 检查请求和跳转方式

alipay.trade.wap.pay 通常返回一个用于跳转至支付宝收银台的 HTML 表单。服务端取得响应后,需要将表单内容直接返回给浏览器。

不要只提取响应中的某个 URL,也不要再次对表单内容进行 HTML 转义。例如,下面的处理可能破坏表单:

<form name="punchout_form" method="post" ...>

浏览器最终收到的必须是可以执行的真实 <form>,不能是转义后显示在页面上的文本。

Java SDK 示例

下面的示例只展示关键调用方式。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/pay/return");
request.setNotifyUrl("https://example.com/pay/notify");

JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", "WAP_" + System.currentTimeMillis());
bizContent.put("total_amount", "0.01");
bizContent.put("subject", "沙箱 H5 支付测试");
bizContent.put("product_code", "QUICK_WAP_WAY");
bizContent.put("quit_url", "https://example.com/order");

request.setBizContent(bizContent.toJSONString());

AlipayTradeWapPayResponse response = alipayClient.pageExecute(request);

if (!response.isSuccess()) {
    throw new IllegalStateException(
        "H5 支付请求失败,code=" + response.getCode()
            + ", subCode=" + response.getSubCode()
            + ", subMsg=" + response.getSubMsg()
    );
}

String paymentForm = response.getBody();

随后,服务端应以 HTML 形式输出 paymentForm:

response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(paymentForm);
response.getWriter().flush();

实际项目中,不要混淆 SDK 返回对象与 Web 框架中的 HttpServletResponse。可以使用更明确的变量名来区分两者。

记录完整错误信息

支付宝收银台显示的“订单信息异常”只是给用户看的概括性提示,不能作为唯一的排查依据。服务端应记录以下信息:

code
msg
sub_code
sub_msg
out_trade_no
app_id
method
product_code
gateway

记录日志时,不要输出商户私钥、完整签名或其他敏感信息。

如果接口同步响应成功,但跳转到收银台后才报错,还要检查浏览器实际提交的表单内容,并确认:

  • 表单没有被网关或前端框架截断。
  • 字符编码统一为 UTF-8。
  • total_amount 没有被二次转换。
  • subject 不为空,也不包含异常控制字符。
  • return_url 和 quit_url 是合法的 HTTP 或 HTTPS 地址。
  • biz_content 没有被重复编码。
  • 手机浏览器能够正常跳转和提交表单。

其他注意事项

return_url 只负责支付完成后的页面跳转,不能用于最终判断支付是否成功。订单状态应以后端异步通知或主动查询结果为准,同时验证通知签名、商户订单号、金额和应用 ID 等信息。

在内置 WebView 中测试时,如果系统浏览器可以支付而 WebView 无法支付,还要检查 WebView 对表单提交、重定向、Cookie、外部应用唤起和混合内容的限制。如果系统浏览器也提示订单异常,则应先排查 API、product_code、订单号和沙箱产品能力。

进行最小化验证时,使用全新的 out_trade_no、固定测试金额和简短的订单标题,只保留 H5 支付所需的参数。最小请求成功后,再逐项恢复业务参数,以便定位引发异常的具体字段或处理环节。

备注:内容仅供参考。