调用沙箱支付接口时遇到 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 问题。
- 沙箱和生产环境的稳定性及行为可能不同。即使沙箱问题已经解决,上线前仍需按照支付平台的要求完成生产环境验证。
- 如果支付平台提供服务状态页、沙箱公告或技术支持渠道,先确认是否有已知故障。如果没有公开状态信息,只能提供请求标识,请平台查询服务端日志。
备注:内容仅供参考。