读懂聚合站返回的限流响应头:哪几个字段真正决定你下一次能不能发
当请求被限流时,响应头比错误消息更有用。本文逐个解释聚合站在代理层可能透出的限流相关响应头,区分哪些字段反映聚合站自身的配额与队列,哪些来自上游厂商,并给出记录日志、做退避决策的实用方法。
为什么限流时要看响应头
被限流时,响应体往往只有一句 rate limit exceeded,真正有用的信息常常藏在响应头里。聚合站在你的请求和上游厂商之间做转发,因此返回的头可能来自两个层面:聚合站自身的配额与排队策略,以及上游厂商透传的限制信号。
学会区分它们,你才能判断该等多久、该换 key,还是该改请求节奏。
常见的限流相关响应头
不同厂商的命名不完全一致,但大体围绕下面几类。聚合站通常会保留原始头,也可能追加自己的前缀。
- 剩余额度类:如
x-ratelimit-remaining-requests、x-ratelimit-remaining-tokens。表示当前窗口内还剩多少请求次数或 token。数值通常按窗口滑动。 - 重置时间类:如
x-ratelimit-reset-requests、x-ratelimit-reset-tokens。表示剩余额度恢复的大致时间,可能是秒数,也可能是1s、6m0s这样的时长字符串。 - 重试建议类:
retry-after。出现 429 或 503 时常见,直接告诉客户端建议等待多久再试。这个字段优先级最高,应当优先遵守。 - 限制总量类:如
x-ratelimit-limit-requests、x-ratelimit-limit-tokens。表示你在当前维度上的上限,用来计算使用比例。 - 请求 ID 类:如
x-request-id、request-id。它不直接决定能不能发,但排查和申诉时必带。
哪些来自聚合站,哪些来自上游
同一个请求穿过聚合站再打到上游,头可能被叠加。区分方法是看语义和命名。
- 偏聚合站的字段:与你的账户余额、站内并发、key 分组、队列位置相关的字段。常见做法是加自定义前缀,如
x-proxy-、x-gateway-,或直接在错误体里给出站内配额说明。 - 偏上游的字段:标准的
x-ratelimit-系列、retry-after、部分厂商特有的anthropic-ratelimit-一类命名。这些反映的是上游对聚合站账号的限制,不一定等于聚合站分给你的额度。
需要提醒的是:上游的剩余额度不等于你能用的额度。聚合站可能对多个用户共享的上游账号做了池化,也可能对每个用户单独限速。因此看到上游头显示还有余量,不代表你立刻就能发;反过来,上游头归零也不一定说明你被拒。
收到 429 时的判断顺序
可以按下面的顺序做决策:
- 先看有没有
retry-after。有就按它等待,不要立即重试。 - 再看站内自定义头。如果聚合站给出了队列长度或站内配额,说明瓶颈在聚合层,重试可能无意义,考虑换 key、换模型或降低并发。
- 最后看上游的
x-ratelimit-*。如果剩余请求数很低而重置时间很近,短暂等待即可;如果重置时间很远,说明需要调整调用节奏。
避免固定间隔的忙重试。固定重试会在限流窗口内持续堆积请求,反而延长恢复时间。
把这些字段记进日志
只靠肉眼排查不够,建议在客户端统一记录。
- 记录状态码、
x-request-id、全部x-ratelimit-*、retry-after,以及聚合站自定义的限流头。 - 记录收到响应的时间戳和本次请求的模型名、key 标识(脱敏后)。
- 日志中把「站内头」和「上游头」分开存放,方便后续统计哪一层先被打满。
- 如果做重试,同时记录重试次数和第几次成功,便于估算真实可用速率。
有了这些数据,你可以画出随时间变化的剩余额度曲线,判断是偶发突发还是持续超限。
一个简单的退避策略
响应头是可以直接驱动退避的:
- 有
retry-after:按值等待,可加小抖动避免同时重试。 - 只有重置时间:等待到重置点附近再加抖动。
- 什么都没透出:采用指数退避加抖动的默认策略,并限制最大重试次数。
在客户端批量并发时,建议对同一 key 做全局的节流,而不是每个请求各自退避,否则多个请求同时等待会放大冲击。
小结
限流响应头里,retry-after 决定「等多久」,x-ratelimit-remaining-* 和 reset 类字段决定「还能不能发」,自定义前缀字段则告诉你瓶颈在聚合站还是上游。把它们完整记进日志,并据此做带抖动的退避,比盲目重试更省事,也更容易定位问题。