跳转到内容

认证、请求头与错误

所有 Gateway 端点用 Bearer:

Authorization: Bearer gw_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

真实的 Gateway Key 是 gw_ 加 43 个字符(32 字节 base64url)。缺失或格式不对返回 401 invalid_api_key

Anthropic 兼容端点也接受 x-api-key两个头同时出现且值不一致时直接判失败,返回 401 —— SDK 配了 base URL 又留着环境变量里的旧 key,就是这个场景。

Gateway 为每个请求生成一个 req_ 加 26 个字符的 ID(16 字节随机数,小写 base32),例如 req_k9x8v5fcwde34gqbn142t2r9qw。它在处理器入口第一步就写入响应,先于鉴权和限流, 所以 401、429 在内的错误响应同样带着它;流式请求的 ID 在首个内容字节之前就已发出。

两个协议门面放的位置不同,各自对齐官方惯例:

端点位置
OpenAI 兼容(/v1/chat/completions 等)响应头 X-Request-ID不在响应体里
Anthropic 兼容(/v1/messages响应头 request-id;错误响应体还带顶层 request_id 字段

响应体里的 idchatcmpl-...)是补全对象的 ID,和请求 ID 是两回事;OpenAI 格式的错误信封 (error.message/type/param/code)里没有请求 ID,只能从响应头拿。

SDK 已经替你解析好了这个头:

# OpenAI Python SDK
response = client.chat.completions.create(...)
print(response._request_id)
# 出错时异常对象上也有
except openai.APIStatusError as e:
print(e.request_id)
// OpenAI Node SDK
const response = await client.chat.completions.create({ ... });
console.log(response._request_id);

Anthropic 官方 SDK 同样通过 _request_id(Python / Node)暴露 request-id 头。 需要完整响应头时,用 SDK 的 with_raw_response(Python)/ withResponse(Node)变体。

用它来报障。 把错误路径的请求 ID 记进应用自己的日志;向 Halro 管理员反馈问题时给出这个 ID, 就能直接定位网关侧对应的记录 —— 比贴 message 文本可靠得多,message 是脱敏后的展示文案, 不保证稳定。

Halro 的 Gateway 不实现 /v1/models。很多 SDK 初始化后第一个动作是 models.list(),会拿到 404,响应体里带一句专门写给这种情况的说明:应用通过 Project 上配置的公开别名来指定模型。别名由管理员在 Route 上定义,Gateway 不向应用泄露它背后连的是哪个上游模型。

同一个状态码,七个触发点,处理方式并不相同。注意 rate_limit_exceeded 这一个 code 横跨两处 —— 一处在鉴权之前

触发点code何时发生
每源地址限流rate_limit_exceeded鉴权之前。匿名调用方能索取的工作量本身是有界的
Project 每分钟请求数rate_limit_exceeded鉴权之后,管理员在 Project 上配置
Project 每分钟 token 数token_rate_limit_exceeded同上
Project 并发concurrency_limit_exceeded同上
Deployment 并发deployment_concurrency_limit_exceeded管理员在 Deployment 上配置
全部可选 Provider 都到并发上限provider_concurrency_limit_exceeded同上
上游服务商限流provider_rate_limit上游,Halro 透传

Token Guard 不在这张表里。它拒绝时返回的是 403 token_guard_blocked(本次尝试的价格超出 Token Guard 的成本上限),不是 429。按 429 写重试逻辑会让它变成一个永远不会通过的死循环。

Retry-After 只在能算出一个正数等待时长时才写入。每源限流与 Project 限流会带上它;Deployment 并发那条不设置;上游透传的 429 只在上游自己带了可解析的头时才有。客户端必须处理这个头缺失的情况,不能无条件读取。