PAYATHON 2026

调用沙箱支付接口时遇到 502 错误,如何解决?

支付阿杰

结论

502 Bad Gateway 通常表示网关或反向代理没有收到上游支付服务的有效响应。这并不代表支付一定失败,也未必是请求参数有误。

排查时,先确认沙箱服务是否正常,再核对请求地址、代理配置、TLS 连接和超时设置。如果只有特定请求返回 502,需要整理请求 ID、时间戳和脱敏后的请求内容,请支付平台查询服务端日志。

常见原因

沙箱服务临时异常

沙箱环境的稳定性通常不如生产环境,发布、维护、限流或内部服务故障都可能导致 502。如果同一请求此前可以正常执行,代码和配置也没有变化,可以先确认平台服务是否出现异常。

接口地址或环境配置错误

常见情况有:

  • 在沙箱域名后拼接了生产环境的路径。
  • 使用了已经失效或发生调整的沙箱地址。
  • 请求经过了错误的网关、VPN 或代理服务器。
  • DNS 将域名解析到了异常节点。
  • 沙箱凭证被用于生产接口,或生产凭证被用于沙箱接口。

具体的域名、路径和凭证规则,应以所接入支付平台的当前文档为准。

上游连接或 TLS 握手失败

支付平台的网关可能无法连接内部服务,本地代理也可能因为 TLS 协议、证书链或 SNI 配置有误而返回 502。这类问题常见于以下情况:

  • TLS 版本或运行时过旧。
  • 企业代理拦截了 HTTPS 流量。
  • 容器或服务器缺少可信根证书。
  • 客户端通过 IP 地址访问,但证书要求使用域名。
  • 双向 TLS 场景没有正确加载客户端证书。

请求超时或连接中断

创建订单、校验签名或执行风控处理的时间过长时,中间网关可能等不到上游结果就已经超时。请求体过大、网络抖动或连接池异常也可能引发类似问题。

特定请求触发服务端异常

按照 HTTP 语义,参数错误通常应返回 4xx。但沙箱服务可能无法正确处理某些边界数据、异常字符或特殊参数组合,发生内部错误后由网关返回 502。

如果只有某个订单或某组参数失败,而其他请求正常,可以重点比较:

  • 金额格式和币种。
  • 必填字段是否缺失。
  • 时间戳和时区。
  • 签名原文与编码方式。
  • Content-Type 是否正确。
  • 请求体是否为合法 JSON。
  • 回调地址是否符合平台要求。
  • 商户订单号是否重复或含有特殊字符。

建议的排查步骤

1. 保存完整响应信息

记录请求时间、请求地址、HTTP 状态码、响应头和响应体,并留意平台返回的请求标识,如 Request-Id、Trace-Id 或类似字段。

日志中不要写入私钥、完整签名密钥、银行卡号、验证码或其他敏感信息。

curl --verbose \
  --connect-timeout 10 \
  --max-time 30 \
  -X POST 'https://sandbox.example.com/payment' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <SANDBOX_TOKEN>' \
  --data '{
    "merchant_order_no": "test-order-001",
    "amount": 100,
    "currency": "CNY"
  }'

示例中的域名、路径、认证方式和字段只用于说明排查方法,不能替代实际支付平台的接口定义。

2. 使用最小请求复现

按照平台文档构造一个只包含必填字段的请求。如果最小请求能够成功,再逐项加入业务字段,找出导致问题的参数。

测试时也可以换一个新的商户订单号,避免重复订单干扰结果。

3. 排除本地网络和代理问题

在不同网络或运行环境中发送同一请求,例如:

  • 从开发电脑直连。
  • 从测试服务器直连。
  • 暂时绕过企业 HTTP 代理。
  • 对比应用程序和 curl 发出的请求。

如果请求只有经过 Nginx 或其他代理时才失败,需要检查代理日志和超时配置,例如:

location /payment/ {
    proxy_pass https://sandbox.example.com/;
    proxy_connect_timeout 10s;
    proxy_read_timeout 30s;
    proxy_send_timeout 30s;
}

不要为了消除 502 而无限增大超时时间。应先确认请求正常完成需要多久,并查清是哪一层发生了超时。

4. 检查 DNS 和 TLS

可以用以下命令检查域名解析和 TLS 握手:

nslookup sandbox.example.com
openssl s_client \
  -connect sandbox.example.com:443 \
  -servername sandbox.example.com

如果握手失败,检查系统时间、证书链、运行时支持的 TLS 版本,以及代理是否替换了服务端证书。关闭证书校验不能作为正式解决方案。

5. 核对接口和签名配置

确认以下配置均来自同一个环境:

  • API 基础地址。
  • 商户号或应用 ID。
  • API 密钥、公钥及证书。
  • 签名算法。
  • 回调地址。
  • 接口版本。

签名失败一般会返回明确的业务错误或 4xx,但沙箱实现不完善时也可能返回 502,所以这些配置仍需逐项核对。

6. 设置有限重试

对于已经确认具有幂等性的请求,可以在遇到临时性 502、503 或 504 时进行有限次数的指数退避重试。调用支付创建类接口时,必须使用唯一订单号或平台提供的幂等键,以免重复扣款或重复创建订单。

async function requestWithRetry(url, options, maxAttempts = 3) {
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    const response = await fetch(url, options);

    if (![502, 503, 504].includes(response.status)) {
      return response;
    }

    if (attempt === maxAttempts) {
      return response;
    }

    const delay = 500 * 2 ** (attempt - 1);
    await new Promise(resolve => setTimeout(resolve, delay));
  }
}

重试前必须确认接口的幂等规则。如果无法确认,不要自动重试支付提交请求,应先查询订单状态。

7. 向平台提交可定位的信息

如果问题能在多个网络环境中稳定复现,向支付平台提供以下信息:

  • 沙箱接口名称和请求路径。
  • 错误发生的准确时间及时区。
  • HTTP 状态码和脱敏后的响应内容。
  • Request-Id 或 Trace-Id。
  • 商户订单号。
  • 脱敏后的请求参数。
  • 问题是否每次都会出现,以及最小复现步骤。

不要通过工单或聊天消息直接发送私钥、密钥、访问令牌和完整支付凭证。

注意事项

  • 收到 502 后,不要马上认定订单没有创建。网关虽然没有返回有效响应,上游仍可能已经处理请求,应先调用订单查询接口确认状态。
  • 不要持续高频重试,否则可能触发限流,还会增加重复订单的风险。
  • 不要通过关闭 HTTPS 证书校验来解决 TLS 问题。
  • 沙箱和生产环境的稳定性及行为可能不同。即使沙箱问题已经解决,上线前仍需按照支付平台的要求完成生产环境验证。
  • 如果支付平台提供服务状态页、沙箱公告或技术支持渠道,先确认是否有已知故障。如果没有公开状态信息,只能提供请求标识,请平台查询服务端日志。

备注:内容仅供参考。