PAYATHON 2026

支付宝沙箱环境创建支付订单报 504 Gateway Time-out

支付阿杰

结论

这是支付宝沙箱网关返回的 HTTP 504 Gateway Time-out。它表示网关未能在规定时间内收到上游服务的响应。返回内容是 Tengine 生成的 HTML 页面,并非支付宝开放平台正常返回的 JSON,说明问题出现在业务响应生成之前,通常与签名、订单参数等常规接口校验无关。

不过,一次 504 并不能说明沙箱已经关闭。常见原因有:

  • 沙箱服务暂时异常或负载过高;
  • 使用了过期、错误或不稳定的网关地址;
  • 本地网络、代理、DNS 或出口链路异常;
  • 请求已经受理,但响应在网关处超时;
  • 使用动态版本 SDK,导致运行时加载的实现发生变化。

如果同一份代码此前可以正常使用,近期也没有改过参数和密钥,但换到多个网络环境后仍持续返回 504,那么沙箱服务异常的可能性较高。

为什么不像业务参数错误

正常情况下,即使 app_id、签名、密钥或业务参数有误,支付宝网关也会返回结构化的 JSON,例如:

{
  "alipay_trade_precreate_response": {
    "code": "40004",
    "msg": "Business Failed",
    "sub_code": "...",
    "sub_msg": "..."
  }
}

当前收到的却是:

<h1>504 Gateway Time-out</h1>
<hr/>Powered by Tengine

这说明客户端已经连接到支付宝沙箱入口,但入口在等待上游服务时超时了。这段 HTML 不能按支付宝业务错误码解析。

日志中的服务器节点:

openapi-14.rz21a.sandbox.alipay.net

只能说明请求到达了某个沙箱网关节点,无法证明订单一定没有创建成功。

建议的排查顺序

1. 核对沙箱网关地址

通过支付宝开放平台当前提供的沙箱配置或 SDK 常量确认网关地址,不要照搬第三方示例中的历史地址。

常见的沙箱网关形式为:

https://openapi-sandbox.dl.alipaydev.com/gateway.do

优先使用 HTTPS。不要将网关地址替换成响应里显示的内部节点域名,也不要直接请求:

openapi-14.rz21a.sandbox.alipay.net

这是网关内部节点信息,不是应用应当配置的接口地址。

2. 检查基础网络和代理

先测试域名解析和 TLS 连接:

curl -v --connect-timeout 10 \
  https://openapi-sandbox.dl.alipaydev.com/gateway.do

这一步不要求得到成功的支付响应,主要检查:

  • 域名能否正确解析;
  • TCP 和 TLS 能否建立连接;
  • 请求是否经过公司代理、VPN 或安全网关;
  • 收到的是支付宝页面、代理错误页,还是连接超时。

然后分别使用本机、服务器和其他网络出口测试。如果只有某个环境失败,优先检查该环境的 DNS、代理、防火墙和出口 IP。

3. 检查 SDK 与网关配置

日志中有以下内容:

alipay_sdk=alipay-sdk-java-dynamicVersionNo

如果项目使用动态版本,或者没有锁定依赖版本,需要确认运行时实际加载的 SDK 版本,并在生产构建中锁定明确版本。不能只根据这个参数断定 SDK 有问题,但要排除依赖在业务代码未修改时发生变化的情况。

Java 客户端配置可参考以下结构:

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

重点检查:

  • appId 是否属于当前沙箱应用;
  • 商户私钥是否与沙箱应用配置的公钥匹配;
  • 验签时使用的是否是支付宝公钥,而不是应用公钥;
  • sign_type 为 RSA2 时,是否使用对应的 RSA2 密钥;
  • 字符集是否统一为 UTF-8;
  • 是否混用了正式环境和沙箱环境的应用、账号或密钥。

这些配置错误通常会触发 JSON 格式的业务错误,而不是 504,但排查时仍需要逐项确认。

4. 用最小参数重新发起预创建请求

排查时先去掉不必要的扩展参数,只保留创建订单所需的核心字段:

AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();

AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
model.setOutTradeNo("TEST_" + System.currentTimeMillis());
model.setTotalAmount("0.01");
model.setSubject("沙箱支付测试");

request.setBizModel(model);

AlipayTradePrecreateResponse response = alipayClient.execute(request);

if (response.isSuccess()) {
    System.out.println("qrCode=" + response.getQrCode());
} else {
    System.err.println("code=" + response.getCode());
    System.err.println("msg=" + response.getMsg());
    System.err.println("subCode=" + response.getSubCode());
    System.err.println("subMsg=" + response.getSubMsg());
    System.err.println("body=" + response.getBody());
}

如果最小请求依然稳定返回 HTML 504,而不是支付宝 JSON,基本可以排除 biz_content 中复杂业务参数引起的问题。

超时后不要直接生成新订单

504 只表示客户端没有及时收到响应,不代表支付宝一定没有处理请求。如果直接更换 out_trade_no 重试,可能会创建多笔业务订单。

可以按以下流程处理:

  1. 保存本次请求使用的 out_trade_no;
  2. 收到 504 后,通过 alipay.trade.query 查询订单;
  3. 如果查到订单,按查询结果继续处理;
  4. 确认查不到订单后,再使用原 out_trade_no 进行有限次数的重试;
  5. 为重试设置间隔和次数上限。

查询示例:

AlipayTradeQueryRequest queryRequest = new AlipayTradeQueryRequest();

AlipayTradeQueryModel queryModel = new AlipayTradeQueryModel();
queryModel.setOutTradeNo(outTradeNo);
queryRequest.setBizModel(queryModel);

AlipayTradeQueryResponse queryResponse =
    alipayClient.execute(queryRequest);

if (queryResponse.isSuccess()) {
    System.out.println("tradeStatus=" + queryResponse.getTradeStatus());
} else {
    System.err.println("subCode=" + queryResponse.getSubCode());
    System.err.println("subMsg=" + queryResponse.getSubMsg());
}

遇到网络超时时,可以采用简单的退避方式,例如等待 2 秒、5 秒和 10 秒后重试,但不能无限重试。

回调地址也需要单独检查

示例中的通知地址是:

https://jmicro.cn/jmpay/wx/notify

路径中包含 wx 不一定有问题。但如果这个接口实际处理的是微信支付回调,就需要换成支付宝专用的回调地址。

notify_url 需要满足以下条件:

  • 可以从公网访问;
  • HTTPS 证书有效;
  • 不要求登录或额外鉴权;
  • 能正确处理支付宝异步通知;
  • 验签成功后返回纯文本 success;
  • 不与微信支付的签名验证和报文格式混用。

通知地址无法访问通常不会直接导致 alipay.trade.precreate 的同步请求返回 504,但错误的回调配置会影响后续支付状态更新,因此也要检查并修正。

如何判断是沙箱侧故障

如果符合以下情况,可以按沙箱服务异常向支付宝开放平台支持渠道提交问题:

  • 使用的是当前有效的官方沙箱网关;
  • HTTPS、DNS 和本地网络均正常;
  • 在不同机器或不同网络出口都能复现;
  • 最小请求仍返回同一类 HTML 504;
  • 问题持续发生,并非单次偶发;
  • 正式环境或其他支付宝接口链路正常;
  • 请求始终没有收到支付宝 JSON 响应。

提交问题时可以提供:

  • 发生时间和时区,例如 2025-06-02 15:36:20 Asia/Shanghai;
  • API 名称:alipay.trade.precreate;
  • 沙箱 app_id;
  • HTTP 状态码;
  • 完整响应体;
  • 网关响应中的服务器节点;
  • SDK 名称和实际版本;
  • 是否能通过其他网络复现。

不要提交应用私钥、完整密钥文件或其他敏感凭据。虽然通常无法通过请求 URL 中的签名值反推出私钥,但公开日志时仍应对 sign、订单号、用户信息和回调参数做脱敏处理。

最终处理建议

先把网关明确配置为当前官方提供的 HTTPS 沙箱地址,再使用固定版本的 SDK 和最小订单参数复测。收到 504 时,应将请求结果视为”未知”:先调用 alipay.trade.query 核实订单状态,再决定是否重试。

如果多个网络环境持续返回相同的 Tengine 504 页面,客户端无法修复支付宝上游的超时。此时应保存发生时间、接口名称、节点和响应内容,并提交给支付宝开放平台排查。沙箱环境通常达不到正式环境的稳定性,因此业务代码也需要处理超时查询、幂等控制和有限重试。

备注:内容仅供参考。