教程
HiAPI 502 / 503 上游错误:原因与修复方法
你调用 POST https://api.hiapi.ai/v1/tasks(或轮询 GET /v1/tasks/{id}),结果返回的不是通常的 200 加 taskId,而是 502 Bad Gateway 或 503 Service Unavailable。两者都是 5xx 响应,说明问题出在服务器或传输侧,而不是你的请求:你并没有发送错误参数、错误密钥或格式错误的负载。503 是 HiAPI 文档中记载的“平台暂时不可用”信号,告诉你应当重试;502 则是链路上某处产生的网关级响应。本指南说明如何确认这一点、如何在不重复劳动的前提下安全重试,以及如何将 502/503 与 504 超时和 TASK_FAILED 结果区分开来。
502 或 503 实际是什么样
你会看到 HTTP 状态行上出现以下之一,而不是正常的 200:
503 Service Unavailable—— 这个是有文档记载的。HiAPI 的异步 API 文档将503列为 “平台暂时不可用;请稍后用指数退避重试”,对应的业务码是TEMPORARILY_UNAVAILABLE(“生成服务暂时不可用。请稍后重试;如果问题持续存在,请联系支持。”)。HiAPI 的同步错误使用扁平 JSON 信封——文档中 400 的情况为{"code": 400, "message": "...", "data": null, "error_code": "INVALID_REQUEST"}——因此 API 返回的 503 也应使用相同的信封,并带有error_code: "TEMPORARILY_UNAVAILABLE"。502 Bad Gateway—— 这个不在 HiAPI 文档记载的状态码中。在标准 HTTP 中,502 表示网关或代理从其尝试访问的下一跳收到了无效或空响应。因此你收到的 502 是由链路上的网关产生的——可能是边缘/CDN 层、负载均衡器,或你自己网络中的代理——而不是 HiAPI 应用返回其通常的 JSON 信封。响应体通常是一个简短的 HTML 或纯文本网关页面,而这个非 JSON 的响应体本身就是一种信号:表明这是传输/网关状况,而不是带有固定、有文档记载负载的应用错误。
无论哪种情况,状态都是 5xx:问题在服务器或传输侧,而不是你的请求。这与 4xx 相反——400(参数错误)、401(密钥错误;HiAPI 返回嵌套的 {"error": {"code": "permission_denied", "type": "hiapi_error", "request_id": "..."}})或 402(余额不足)——这些都需要你改变自己这边的某些东西来修复。502/503 无法通过修改负载来修复。
常见原因(按可能性从高到低排列)
- 短暂的平台过载或维护窗口 →
503TEMPORARILY_UNAVAILABLE。这是预期内的、有文档记载的情况。它会自行恢复,退避重试即可成功。 - 链路上某个网关或代理的瞬间抖动 →
502。边缘/CDN 层、负载均衡器或你自己网络中的代理短暂未能转发响应。同样是暂时性的。 - 流量突增触发了限制。 在高负载下,你可能反而看到
429RATE_LIMITED(“请稍后重试;避免立即重新提交同一请求”)。如果状态是 429,解决办法是降低发送速率,而不是更用力地重试。 - 所请求的模型后端暂时不可用。 HiAPI 在任务级别将其记录为
MODEL_UNAVAILABLE(“请稍后重试,或切换模型”);服务该模型的平台级短暂故障也可能表现为 503。 - 不是密钥错误、请求体格式错误或余额不足。这些分别是
401/400/402,都不会表现为 502 或 503。
按顺序修复的方法
- 确认是 5xx,而不是 4xx。 先看状态码。
502/503属于服务器/传输侧;400、401、402、404、409、415、422和429属于你这一侧。如果确实是 502/503,不要开始重写请求体——那只对 4xx 有帮助。 - 使用带抖动的指数退避重试。 文档明确要求对 503 使用指数退避。安全的客户端模式是起始约 1 秒,每次尝试翻倍(2 秒、4 秒、8 秒……),上限约 30–60 秒,并加入随机抖动,以免大量客户端同步重试。这些间隔是推荐的客户端模式,不是 HiAPI 发布的时间保证。
- 让提交具备幂等性。 在
POST /v1/tasks上设置Idempotency-Key头(任意 UTF-8 字符串,最长 255 字节)。如果 502/503 让你不确定任务是否实际已创建,使用相同密钥重试是安全的:相同密钥 + 相同请求体将返回原始的taskId,并带有响应头Idempotent-Replay: true,而不会创建第二个任务或产生第二笔扣费。密钥按账户限定作用域,24 小时后过期。完整约定见 Unified Async API 文档。 - 不要在没有密钥的情况下盲目重新 POST。 如果你提交时没有
Idempotency-Key并收到了 502/503,你可能已经创建了一个你看不到的任务——你没有可轮询的taskId,因此朴素的重试有重复工作和重复扣费的风险。在任何规模的重试之前先加上密钥。 - 如果 502/503 发生在轮询期间,继续轮询即可。
GET /v1/tasks/{id}返回的 5xx 不会改变任务状态。终态(success/fail)一旦到达就固定,永远不会互相转换,因此退避后再次轮询即可。或者,注册callback.url,这样你会在终态时收到通知,而不必穿过暂时性的 5xx 进行轮询——投递是至少一次的,因此请按taskId去重。 - 将其与任务级失败区分开来。 如果你反而收到 HTTP
200加"status": "fail",那不是 502/503——任务已被接受、运行并失败。请按各自的方式处理TASK_FAILED(“重试一次;如果问题持续存在,请联系支持”)或TASK_TIMEOUT(“重试该任务”),而不是盲目进行网关重试。 - 如果持续存在,升级处理而不是猛击。 如果 502/503 在几分钟内经过多次退避重试后仍持续出现,应将其视为暂时性的平台事件,而不是可以蛮力解决的问题。停止激进重试,并在错误体包含
request_id时携带它联系支持。你可以从 HiAPI 控制台确认自己的账户和连通性是否正常。
502 / 503 与 504 与 TASK_FAILED 的对比
这些很容易混淆,因为它们都意味着“没有干净地返回”,但需要不同的处理方式:
| 响应 | HTTP 状态码 | 来源 | 任务是否扣费? | 该怎么做 |
|---|---|---|---|---|
503 Service Unavailable |
503(有文档记载) |
HiAPI 平台——暂时不可用或过载 | 无法从响应判断;任务可能已存在 | 使用退避和相同的 Idempotency-Key 重试 |
502 Bad Gateway |
502(不在 HiAPI 文档中) |
链路上的网关/代理(边缘、负载均衡器或你自己的代理) | 无法从响应判断 | 使用退避进行幂等重试;如果只从你的网络出现,怀疑你这一侧有代理 |
504 Gateway Timeout |
504(不在 HiAPI 文档中) |
链路上停止等待的网关或代理(HiAPI 文档未列出 504) | 无法从响应判断 | 与 502 相同;HiAPI 将自己的超时报告为 TASK_TIMEOUT |
TASK_TIMEOUT |
200 + "status": "fail" |
HiAPI——任务已运行但超出时间预算 | 否(预留金额已退还) | 作为新请求重试该任务 |
TASK_FAILED |
200 + "status": "fail" |
HiAPI——任务已被接受并运行,然后失败 | 否(预留金额已退还) | 重试一次,然后读取 error.message |
429 RATE_LIMITED |
429 |
HiAPI——你发送得太快 | 无任务 | 退避;不要立即重新提交 |
400 / 401 / 402 |
4xx |
HiAPI——客户端侧(请求体/密钥/余额错误) | 否 | 修复请求、密钥或余额;重试无济于事 |
一句话判断:502/503/504 是 HTTP 传输错误,不携带任何任务结果;而 TASK_FAILED / TASK_TIMEOUT 以 HTTP 200 加 "status": "fail" 和 error 对象的形式到达。前者意味着“你不知道请求是否送达”;后者是“请求已送达,任务已运行,并且失败了”。
最小验证示例
用一次干净的提交来证明你的密钥和连通性正常,并将 502/503 隔离为暂时性问题。使用一个你确定可用的模型 id(例如 gpt-image-2/text-to-image),并包含 Idempotency-Key,以便重试是安全的:
# A healthy submit returns 200 with a taskId. If this works but a specific
# call just 502/503'd, that 502/503 was transient — not your setup.
curl -sS -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: my-job-0001" \
-d '{"model":"gpt-image-2/text-to-image","input":{"prompt":"a red bicycle on a white background"}}'
# Then poll the task you just created (swap in the returned id):
curl -sS https://api.hiapi.ai/v1/tasks/TASK_ID \
-H "Authorization: Bearer $HIAPI_API_KEY"
如果提交本身返回 200 和一个 taskId,说明你的身份验证和网络路径正常,之前的 502/503 是暂时性的服务器/传输状况——重试失败的调用(复用相同的 Idempotency-Key 会返回原始任务,而不是重复任务)。如果提交反而返回 401 或 400,那是客户端侧问题,不是 502/503。
相关阅读
- HiAPI 任务超时与 504 错误:如何修复 —— 为什么原始
504不是来自 HiAPI,以及TASK_TIMEOUT的含义。 - HiAPI TASK_FAILED 错误:原因与修复方法 —— 处理返回
200+"status": "fail"的任务。 - 当 hiapi /v1/tasks 作业挂起或超时:诊断与重试 —— 深入介绍轮询间隔和重试策略。
- 如何修复 HiAPI 速率限制 (429) 错误 —— 当真正的问题是发送速率而非可用性时。
- 为什么失败的 HiAPI 请求仍会被扣费? —— 失败任务的预留和退款如何运作。
常见问题
502 或 503 是我的错吗?
不是。两者都是 5xx 响应,属于服务器侧或传输侧。你的 API 密钥和请求体不是触发因素——4xx(400/401/402)才是你造成且可以修复的那一类。对 502/503 的正确响应是幂等重试,而不是改代码。
在 HiAPI 上 502 和 503 有什么区别?
503 是 HiAPI 文档记载的“平台暂时不可用”代码(error_code: TEMPORARILY_UNAVAILABLE),来自平台本身。502不在 HiAPI 文档记载的状态码中;在标准 HTTP 中,它由链路上的网关或代理在上游返回无效响应时发出。两者都是暂时性的,都需要退避重试,但 502 也可能指向你自己网络中的代理。
503 与 504 有何不同?
503 表示服务当前暂时不可用或过载。504 Gateway Timeout 表示某处等待响应时间过长。HiAPI 文档未列出 504;如果你看到它,说明链路上某处的网关或代理放弃等待。HiAPI 自己的“耗时过长”状态是任务结果 TASK_TIMEOUT(HTTP 200 + "status": "fail")。参见上方的 504 指南。
如何将 502/503 与 TASK_FAILED 结果区分开?
看 HTTP 状态码。502/503 是没有任务负载的 HTTP 错误。TASK_FAILED 以 HTTP 200 加 "status": "fail" 和 error 对象的形式返回——任务已被接受并运行。对 502/503 使用退避重试;对 TASK_FAILED 重试一次,然后读取 error.message。
收到 502/503 后重试会扣我两次费或创建重复任务吗?
如果你在 POST /v1/tasks 上发送 Idempotency-Key 头,就不会。复用相同的密钥 + 请求体会返回原始的 taskId(Idempotent-Replay: true),而不会创建重复任务。而且失败的任务永不扣费——任务一旦到达失败终态,创建时预留的金额将全额退还。
应该退避多久,何时应该升级处理?
使用带抖动的指数退避(例如 1 秒、2 秒、4 秒、8 秒,设上限,并加入随机性)。如果 502/503 在几分钟内经过多次重试后仍持续返回,停止激进重试,并携带错误体中的 request_id 联系支持——持续的 5xx 通常意味着暂时性的平台事件,而不是更快的重试循环能解决的问题。
看到 502/503 时我应该修改请求负载吗?
不用。502/503 不是验证错误,因此修改参数无济于事,还可能掩盖真正的暂时性原因。保持请求不变,如果尚未添加则加上 Idempotency-Key,然后使用退避重试。