HTTPQUERY
English

429 Too Many Requests

用法

429 Too Many Requests 状态码表示 HTTP 请求数量已超过允许的阈值。例如当服务器想要限制每小时的 API 调用次数时就会发生这种情况。

规范未定义服务器如何统计 HTTP 请求或识别用户。速率限制可以按资源、按用户、跨整个服务器或跨多个服务器进行。用户识别通过凭据完成,或者也可以使用 Cookie。

服务器可以选择包含一个 Retry-After HTTP 头,以告知客户端何时可以再次接受请求。

注意

速率限制(rate limiting)对时间窗口内的请求总数设置上限(硬性截断),而限流(throttling)则通过排队或延迟响应来减慢请求处理。等待时长取决于 Retry-After 头。若没有 Retry-After,常见的时间窗口从 60 秒到 24 小时不等,视 API 而定。VPN 用户会与许多其他用户共享 IP 地址,因此按 IP 的速率限制会影响同一服务器上所有的 VPN 用户。

SEO 影响

Googlebot 将 429 视为服务器错误信号。当站点返回 429 响应时,Google 会暂时降低整个站点的抓取速率。一旦恢复正常响应,抓取速率会逐渐回升。与其他 4xx 状态码不同,429 响应会影响抓取预算(crawl budget)。已被索引的 URL 上持续返回 429 会导致其从搜索结果中移除。要让 Googlebot 减速,429 是正确的状态码。401 和 403 不会降低抓取速率。Bingbot 同样会在 429 响应时降低其抓取速率。此外,Bing 还支持在 robots.txt 中使用 crawl-delay,作为基于状态码限流的替代方案。

示例

客户端请求某个资源,服务器返回 429 Too Many Requests。

请求

GET /current-news HTTP/1.1
Host: example.com

响应

HTTP/1.1 429 Too Many Requests
Retry-After: 1800
Content-Type: text/html
Content-Length: 173

<html>
  <head>
    <title>Request Limit Exceeded</title>
  </head>
  <body>
   <p>The request limit has been reached.
   Try again in 30 minutes.</p>
  </body>
</html>

如何修复

检查响应中的 Retry-After 头。其值要么是秒数,要么是一个 HTTP 日期,表示服务器何时再次接受请求。在指示的时间之前暂停所有请求。

在重试尝试之间实现带抖动(jitter)的指数退避。每次失败后将等待时间翻倍(1s、2s、4s、8s),并加入一个随机偏移,以防止多个客户端在同一时刻重试而制造新的流量峰值。

在触及上限之前监控速率限制头。许多 API 会包含 X-RateLimit-Limit、X-RateLimit-Remaining 和 X-RateLimit-Reset 头。跟踪剩余计数并主动放慢请求。

标准化的速率限制字段

除了事实标准的 X-RateLimit-* 头之外,IETF 正在将 RateLimit 和 RateLimit-Policy 响应字段标准化,用于配额和重置信号。

在客户端对外发请求排队。带有受控派发速率的请求队列可防止突发流量超出限制。当端点支持批量操作时,将多个操作合并为单次 API 调用。

对于在请求之间预期不会变化的数据,缓存响应。重复的相同调用是不必要地消耗速率限制的最常见来源。

在服务器端的 nginx 中,limit_req_zone 和 limit_req 指令控制按 IP 或按端点的速率限制。设置 limit_req_status 429; 使被限流的请求返回正确的状态码,而不是默认的 503。使用 burst 和 nodelay 参数在不立即拒绝客户端的情况下允许短暂的流量峰值。

对于 AWS API Gateway,在阶段(stage)或方法级别配置限流设置。当默认阈值过于严格时,提高速率和突发容量以匹配预期的流量模式。

代码参考

.NET

HttpStatusCode.TooManyRequests

Rust

http::StatusCode::TOO_MANY_REQUESTS

Rails

:too_many_requests

Go

http.StatusTooManyRequests

Symfony

Response::HTTP_TOO_MANY_REQUESTS

Python3.5+

http.HTTPStatus.TOO_MANY_REQUESTS

Apache HttpComponents Core

org.apache.hc.core5.http.HttpStatus.SC_TOO_MANY_REQUESTS

Angular

@angular/common/http/HttpStatusCode.TooManyRequests