PAYATHON 2026

H5 接入支付提示跨域,沙盒 GET 请求持续报错如何解决?

支付小周

结论

alipay.trade.app.pay 是原生 App 支付接口,不能直接用于 H5 页面。浏览器通过 AJAX、fetch 或前端拼接 GET 请求访问支付宝网关,通常会遇到跨域限制。这个问题无法靠前端添加 CORS 请求头解决。

H5 支付应使用 alipay.trade.wap.pay。业务服务器负责生成签名和支付请求,浏览器再通过表单提交或页面跳转进入支付宝收银台。

为什么会出现跨域错误

常见原因有以下几种:

  1. 使用了错误的接口

    alipay.trade.app.pay 面向原生 App。服务端调用后得到的是供支付宝客户端 SDK 使用的订单字符串,并不是 H5 浏览器可以直接打开的支付页面。

  2. 前端直接访问支付宝网关

    浏览器的同源策略会限制跨域 AJAX 请求。支付宝支付网关不是向任意网页开放的 CORS API,因此即使参数和签名都正确,请求也可能先被浏览器拦截。

  3. 使用 GET 拼接支付参数

    GET 请求容易出现 URL 编码错误、参数过长、+ 被转为空格、签名值被二次编码等问题。支付页面类接口更适合通过表单 POST 提交。

  4. 混用了沙盒和正式环境的配置

    沙盒应用必须使用沙盒网关和沙盒账号。正式应用参数、正式网关、沙盒密钥和沙盒账号不能混用。

正确的调用流程

H5 支付流程如下:

H5 页面
  → 请求业务服务器创建订单
  → 业务服务器生成 alipay.trade.wap.pay 请求并签名
  → 返回支付表单或支付跳转地址
  → 浏览器跳转到支付宝收银台
  → 支付宝异步通知业务服务器
  → 业务服务器验签并更新订单

私钥、签名过程和订单金额都必须放在服务端,不能写入 JavaScript 或暴露给浏览器。

服务端请求参数示例

下面的示例只用于说明参数结构。签名应通过支付宝官方 SDK,或经过验证的服务端签名实现来生成:

<?php

$params = [
    'app_id'      => '你的沙盒应用 APPID',
    'method'      => 'alipay.trade.wap.pay',
    'format'      => 'JSON',
    'charset'     => 'utf-8',
    'sign_type'   => 'RSA2',
    'timestamp'   => date('Y-m-d H:i:s'),
    'version'     => '1.0',
    'notify_url'  => 'https://example.com/payment/alipay/notify',
    'return_url'  => 'https://example.com/payment/result',
    'biz_content' => json_encode([
        'out_trade_no' => 'ORDER_202609090001',
        'total_amount' => '0.01',
        'subject'      => '测试订单',
        'product_code' => 'QUICK_WAP_WAY',
        'quit_url'     => 'https://example.com/order'
    ], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
];

// 使用支付宝服务端 SDK 按照 RSA2 规则生成 sign
$params['sign'] = createAlipaySign($params);

不要直接照搬示例中的订单号、金额和地址。out_trade_no 应由业务系统生成,并确保在商户侧唯一。

通过表单进入收银台

服务端生成签名后,可以返回一个自动提交的 HTML 表单:

<form id="alipay-form"
      method="post"
      action="https://openapi-sandbox.dl.alipaydev.com/gateway.do">
  <input type="hidden" name="app_id" value="沙盒应用 APPID">
  <input type="hidden" name="method" value="alipay.trade.wap.pay">
  <input type="hidden" name="format" value="JSON">
  <input type="hidden" name="charset" value="utf-8">
  <input type="hidden" name="sign_type" value="RSA2">
  <input type="hidden" name="timestamp" value="2026-09-09 12:00:00">
  <input type="hidden" name="version" value="1.0">
  <input type="hidden" name="notify_url"
         value="https://example.com/payment/alipay/notify">
  <input type="hidden" name="return_url"
         value="https://example.com/payment/result">
  <input type="hidden" name="biz_content"
         value='{"out_trade_no":"ORDER_202609090001","total_amount":"0.01","subject":"测试订单","product_code":"QUICK_WAP_WAY"}'>
  <input type="hidden" name="sign" value="服务端生成的签名">
</form>

<script>
  document.getElementById('alipay-form').submit();
</script>

实际开发时,最好直接使用服务端 SDK 提供的页面支付或表单生成功能,以免手工处理待签名字符串、参数排序和 URL 编码时出错。

如果必须使用 alipay.trade.app.pay

只有原生 App 接入支付宝客户端 SDK 时,才应使用这个接口:

  1. App 请求业务服务器创建支付订单。
  2. 服务器调用 alipay.trade.app.pay,生成签名后的订单字符串。
  3. 服务器将订单字符串返回给 App。
  4. App 把订单字符串传给支付宝客户端 SDK。
  5. 服务器根据异步通知确认最终支付状态。

即使采用这种方式,也不能让 WebView 或浏览器直接跨域请求支付宝网关。

排查步骤

1. 检查调用位置

先确认请求是否由下面这类前端代码直接发出:

fetch('https://openapi-sandbox.dl.alipaydev.com/gateway.do?...')

或者:

axios.get('https://openapi-sandbox.dl.alipaydev.com/gateway.do', {
  params: paymentParams
})

如果是,请停止前端直调,改为请求自己的业务服务器。

2. 检查接口类型

H5 收银台使用:

alipay.trade.wap.pay

原生 App 使用:

alipay.trade.app.pay

3. 检查沙盒配置

逐项核对以下内容:

  • app_id 是否属于当前沙盒应用;
  • 网关是否为当前开放平台文档提供的沙盒网关;
  • 应用私钥是否与上传的应用公钥匹配;
  • 验签时使用的是否为支付宝公钥;
  • sign_type 是否与密钥及签名实现一致;
  • 沙盒支付是否使用了沙盒账号。

沙盒网关地址可能随着平台配置或文档调整而变化,应以当前开放平台控制台和官方文档显示的地址为准。

4. 检查签名和编码

生成签名前,需要排除 sign 参数,并按照支付宝接口要求构造待签名字符串。还要核对:

  • charset 是否统一为 utf-8;
  • biz_content 是否为合法 JSON;
  • JSON 内容是否在签名后被修改;
  • 签名是否经过重复 URL 编码;
  • GET 查询串中的 + 是否被错误转换为空格;
  • 参数值前后是否混入空格或换行。

5. 区分跳转回调和支付通知

return_url 只是用户支付后浏览器跳转的地址。用户可能关闭页面,也可能伪造查询参数,因此不能通过它判断支付是否成功。

订单状态应以 notify_url 收到的异步通知为准。服务端收到通知后,需要:

  • 验证签名;
  • 校验 app_id;
  • 校验商户订单号;
  • 校验金额和币种;
  • 确认交易状态;
  • 做幂等处理,避免重复更新订单;
  • 按照接口要求返回成功响应。

注意事项

不要通过关闭浏览器安全策略、安装跨域插件或使用公共代理来”解决”支付跨域问题。这些做法无法修正错误的接入流程,还可能造成密钥、订单和用户数据泄露。

如果改用 alipay.trade.wap.pay,并由服务端生成表单后仍然报错,应检查支付宝返回的业务错误码和 sub_msg,不能只看浏览器控制台里的跨域信息。跨域通常说明调用入口不对。签名、应用配置或参数有误时,则需要根据网关返回的具体内容分别排查。

备注:内容仅供参考。