Ошибка 429 Too Many Requests: что значит и как обходиться с рейт-лимитами

10 минут чтения
Средний рейтинг статьи — 4.8

Что такое ошибка 429 Too Many Requests и как её исправить

Ошибка 429 Too Many Requests появляется, когда сервер понял запрос, но отказывается его выполнять из-за превышения лимита частоты. Проще говоря: клиент отправляет слишком много запросов за короткое время, и сервис просит притормозить.

Для владельца сайта 429 может быть как нормальной защитной реакцией, так и симптомом проблемы: боты сканируют сайт, фронтенд зациклил запросы, интеграция не уважает лимиты API, мониторинг проверяет слишком часто, CDN или WAF ограничивает весь трафик с одного IP. Для разработчика это не просто «ещё один HTTP-код», а сигнал о backpressure, квотах и корректной работе клиента под нагрузкой.

Разберём, что означает ошибка 429, чем она отличается от соседних кодов, как обрабатывать Retry-After, какие алгоритмы рейт-лимитинга за ней стоят и что делать, чтобы лимиты защищали сервис, а не ломали пользователей.

Что означает ошибка 429 Too Many Requests

429 Too Many Requests — HTTP-статус из класса 4xx. Он означает, что проблема на стороне клиента: запросов слишком много относительно правил, заданных сервером.

Типичный ответ выглядит так:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 60
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 60
 
{
  "error": "rate_limit_exceeded",
  "message": "Too many requests. Try again later."
}

Главная деталь — заголовок Retry-After. Он подсказывает, когда можно повторить запрос:

  • Retry-After: 60 — повторить через 60 секунд;
  • Retry-After: Wed, 21 Oct 2026 07:28:00 GMT — повторить после указанного времени.

Кроме него часто встречаются заголовки:

  • RateLimit-Limit — общий лимит в окне;
  • RateLimit-Remaining — сколько запросов осталось;
  • RateLimit-Reset — через сколько секунд лимит обновится;
  • X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset — более старый, но всё ещё популярный вариант тех же заголовков.

429 не говорит, что сервер «сломался». Часто это признак того, что защита работает: сервис не даёт одному клиенту занять все ресурсы. Но если обычные пользователи массово видят 429 на главной странице, в личном кабинете или при оформлении заказа — это уже инцидент доступности.

Чем 429 отличается от 403, 500 и 503

HTTP-коды похожи только внешне. Для диагностики важно понимать, что именно сообщает сервер. Общий обзор статусов — в справочнике «Все коды ответов HTTP», здесь — контекст именно для 429.

1) 429 Too Many Requests — клиент превысил лимит частоты. Доступ не запрещён навсегда: нужно подождать, снизить частоту, использовать кэш, распределить нагрузку или изменить тариф/API-квоту.

2) 403 Forbidden — сервер понял запрос, но доступ запрещён по правам, политике безопасности, WAF-правилу или IP-блокировке. В отличие от 429, ожидание само по себе обычно не помогает. Подробнее — в статье «Ошибка 403 Forbidden».

3) 500 Internal Server Error — внутренняя ошибка приложения. Клиент мог отправить корректный запрос, но сервер не смог его обработать: баг, исключение, проблема с зависимостью или конфигурацией. См. «Ошибка 500».

4) 503 Service Unavailable — сервис временно недоступен: перегрузка, обслуживание, нет свободных воркеров, упала зависимость. Иногда вместо 429 серверы ошибочно возвращают 503 при рейт-лимите — это хуже для клиентов: они не понимают, что нужно снизить частоту, а не просто ретраить агрессивнее.

5) 401 Unauthorized — нет корректной аутентификации. Может сочетаться с лимитами: например, анонимным пользователям разрешено 30 запросов в минуту, а авторизованным — 300.

Правильный код помогает клиенту выбрать поведение: при 429 — ждать и снижать скорость, при 500 — делать ограниченные повторы, при 403 — не долбить сервер, а проверять права доступа.

Почему возникает ошибка 429

Причины делятся на клиентские, инфраструктурные и продуктовые.

1) Слишком частые запросы из фронтенда — поиск без debounce, автосохранение на каждое нажатие клавиши, бесконечный polling, компонент перерендерился и снова вызвал API. В браузере это выглядит как пачка одинаковых запросов в Network tab.

2) Агрессивные ретраи — клиент получил ошибку, но вместо паузы начал повторять запросы без задержки. Если таких клиентов много, возникает лавина повторов — это близко к thundering herd: система и так под нагрузкой, а клиенты добивают её синхронными повторами.

3) Несколько инстансов сервиса используют один API-ключ — каждый инстанс считает, что отправляет мало запросов, но суммарно они пробивают общий лимит. Часто случается после масштабирования в Kubernetes, Docker Compose или автоскейлинге.

4) Общий IP у большого числа пользователей — NAT, корпоративный прокси, мобильный оператор, VPN или CDN приводят к тому, что множество реальных пользователей выглядят как один клиент. Если лимит считается только по IP, легитимный трафик попадает под 429.

5) Боты, парсеры и сканеры — поисковые роботы, SEO-инструменты, сканеры уязвимостей, парсеры цен и брутфорсеры создают всплески запросов. Здесь 429 полезен: он снижает нагрузку и усложняет автоматизированные атаки.

6) Неверно настроенный reverse proxy, WAF или CDN — лимит может сработать не в приложении, а на уровне Nginx, API Gateway, Cloudflare, балансировщика или ingress-контроллера. Разработчик видит «наш API вернул 429», хотя запрос до приложения даже не дошёл.

7) Слишком жёсткие продуктовые квоты — бесплатный тариф, лимит на endpoint, ограничение на импорт, лимит на отправку SMS или email. Здесь 429 — часть бизнес-логики, а не авария.

8) Неправильный мониторинг или health checks — если проверка доступности ходит слишком часто или во все endpoint'ы подряд, она сама становится источником 429. Обычно для этого достаточно одной-двух лёгких страниц или отдельного health-endpoint, а не тяжёлых пользовательских сценариев.

Как понять, чей лимит сработал

Первый шаг — определить, где именно сформирован ответ 429: в приложении, Nginx, API Gateway, CDN, WAF или внешнем API.

Начните с простого запроса:

curl -i https://example.com/api/products

Смотрите на заголовки и тело ответа.

1) Заголовки сервераServer, Via, CF-Ray, X-Cache, X-Request-ID, X-RateLimit-*, RateLimit-* часто подсказывают источник. Есть CF-Ray — ответ мог прийти от Cloudflare. Тело — HTML с шаблоном Nginx — вероятно, лимит сработал на reverse proxy.

2) Логи reverse proxy — в Nginx для limit_req можно логировать срабатывания. Если в access/error log есть сообщения о limiting, приложение ни при чём. Практическая настройка — в статье «Как настроить Nginx rate limiting для защиты от DDoS и брутфорса».

3) Логи приложения — добавьте в ответ и логи request_id, user_id, api_key_id, rate_limit_key, route, remaining, reset_at. Без этих полей сложно понять, кто именно превысил лимит.

4) Метрики по статусам — график http_requests_total{status="429"} по маршрутам и клиентам быстро показывает масштаб проблемы. Растёт только на /login — вероятно, защита от брутфорса. На /api/search — проблема в UI или ботах. На всех маршрутах сразу — общий лимит, перегрузка или ошибка конфигурации.

5) Сравнение внешнего и внутреннего трафика — проверьте, получает ли 429 обычный пользователь из браузера, ваш backend при обращении к внешнему API или только синтетические проверки. Это разные инциденты с разными решениями.

6) Проверка ключа лимитирования — лимит по IP, пользователю, API-ключу, сессии и endpoint'у ведёт себя по-разному. Ошибка в выборе ключа — частая причина ложных блокировок.

Как клиенту правильно обходиться с рейт-лимитами

Речь не про обход чужих ограничений через прокси и подмену идентичности, а про корректную работу в рамках опубликованных лимитов. Это снижает число ошибок, риск бана аккаунта и нагрузку на обе стороны.

1) Уважайте Retry-After — если сервер вернул этот заголовок, используйте его как минимальную паузу перед повтором, а не ретраите сразу «на всякий случай».

2) Используйте exponential backoff с jitter — если Retry-After нет, увеличивайте задержку между попытками: 1, 2, 4, 8 секунд, добавляя случайный разброс. Jitter нужен, чтобы много клиентов не проснулись одновременно.

Пример на JavaScript:

async function requestWithBackoff(url, options = {}, maxRetries = 5) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const response = await fetch(url, options);
 
    if (response.status !== 429) {
      return response;
    }
 
    const retryAfter = response.headers.get('Retry-After');
    let delayMs;
 
    if (retryAfter && /^\d+$/.test(retryAfter)) {
      delayMs = Number(retryAfter) * 1000;
    } else {
      const base = Math.min(1000 * 2 ** attempt, 30000);
      const jitter = Math.floor(Math.random() * 1000);
      delayMs = base + jitter;
    }
 
    await new Promise((resolve) => setTimeout(resolve, delayMs));
  }
 
  throw new Error('Rate limit exceeded after retries');
}

3) Ограничивайте параллелизм — лимит часто пробивается не количеством запросов в минуту, а всплеском одновременных запросов. Очередь на клиенте с concurrency = 3 может быть эффективнее десятков параллельных fetch.

4) Кэшируйте ответы — если данные меняются редко, не запрашивайте их каждый раз. Используйте HTTP-кэширование, ETag, If-None-Match, локальный кэш, CDN или Redis на сервере. Особенно полезно для справочников, профилей, настроек, каталогов.

5) Убирайте лишний polling — заменяйте частые опросы на webhooks, SSE, WebSockets или увеличивайте интервал. Если polling всё же нужен, делайте частоту адаптивной: чаще при активном пользователе, реже в фоне.

6) Делайте операции идемпотентными — повтор запроса после 429 или сетевой ошибки не должен создавать дубликаты заказов, платежей и задач. Для этого используют Idempotency-Key. Подробнее — в статье «Что такое idempotency в API и как избежать дубликатов запросов».

7) Разделяйте критичные и фоновые запросы — загрузка страницы, оформление заказа и фоновая синхронизация не должны конкурировать за один локальный лимит клиента. Фоновые задачи можно откладывать, объединять и выполнять пачками.

8) Не скрывайте 429 от пользователя полностью — если лимит связан с его действием, покажите понятное сообщение: «Слишком много попыток. Попробуйте через минуту». Для API-клиентов возвращайте машинно-читаемый код ошибки и время сброса лимита.

Как проектировать рейт-лимиты на стороне API

Хороший рейт-лимит защищает систему, но не ломает нормальные сценарии. Плохой — создаёт ложные 429, заставляет клиентов писать хаки и ухудшает UX.

1) Определите, что именно защищаете — CPU, базу данных, внешний API, очередь, платёжный шлюз, endpoint логина или весь сервис целиком. Один глобальный лимит редко решает всё: для тяжёлых маршрутов нужны отдельные правила.

2) Выберите ключ лимитирования — IP подходит для анонимного трафика, но плохо работает за NAT. user_id хорош для авторизованных действий, api_key — для интеграций. Часто нужна комбинация: ip + route, user_id + route, api_key + method.

3) Используйте разные лимиты для разных действийGET /products выдержит много запросов, а POST /login, POST /payments или генерация отчёта должны иметь более строгие ограничения.

4) Возвращайте понятные заголовки — клиенту нужны Retry-After, RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset. Без них он будет угадывать и, скорее всего, ретраить неправильно.

5) Не путайте рейт-лимит и авторизацию — превысил частоту — возвращайте 429, нет прав — 403.

6) Делайте лимиты наблюдаемыми — логируйте срабатывания, ключ лимита, маршрут, текущий счётчик и решение: allow, delay, reject. Метрики должны показывать не только число 429, но и близость к лимиту.

7) Учитывайте распределённость — если приложение запущено в нескольких инстансах, локальный in-memory счётчик даёт неконсистентный лимит. Для общих квот обычно используют Redis, Memcached или встроенные возможности API Gateway.

8) Выберите алгоритм под задачу — fixed window проще, но допускает всплески на границе окна; sliding window сглаживает поведение; token bucket разрешает короткие bursts; leaky bucket выравнивает поток. Сравнение — в статье «Алгоритмы рейт-лимитинга: token bucket, leaky bucket, sliding window».

9) Продумайте graceful degradation — не все запросы нужно сразу отклонять. Иногда лучше вернуть кэшированные данные, поставить задачу в очередь, снизить детализацию ответа или ограничить только дорогую часть операции. Это связано с backpressure: сервис должен сигнализировать о перегрузке и не принимать больше работы, чем способен обработать. См. «Backpressure: как не положить сервис под нагрузкой».

Как исправить 429 на сайте и в инфраструктуре

Если 429 уже появилась в продакшене, двигайтесь от симптома к источнику.

1) Проверьте масштаб — единичные 429 у бота и массовые 429 у пользователей — разные ситуации. Смотрите долю 429 по маршрутам, IP, user-agent, странам, API-ключам и времени.

2) Найдите слой, который отвечает 429 — CDN, WAF, Nginx, ingress, API Gateway, приложение или внешний API (см. раздел выше о диагностике). Не меняйте лимиты в приложении, если блокирует CDN.

3) Проверьте недавние изменения — релиз фронтенда, новый cron, включение мониторинга, изменение интервала polling, масштабирование воркеров, обновление WAF-правил, смену CDN, изменение лимитов тарифа у внешнего API.

4) Смягчите ложные срабатывания — если страдают легитимные пользователи, временно увеличьте лимит, добавьте burst, разделите лимит по endpoint'ам, исключите health-endpoint или смените ключ лимитирования с IP на пользователя/API-ключ.

5) Ограничьте источник шума — если 429 вызваны ботами, настройте отдельные правила для подозрительных user-agent, IP-диапазонов и маршрутов. Но не превращайте рейт-лимит в грубую блокировку всего трафика.

6) Исправьте клиентское поведение — добавьте debounce/throttle, уберите циклические запросы, внедрите backoff, уменьшите параллелизм, включите кэш. Если проблема во внешнем API — проверьте документацию: лимиты часто отличаются по тарифу и типу метода.

7) Разведите лимиты для людей и автоматики — браузерные пользователи, мобильные приложения, серверные интеграции, webhooks и внутренние задачи должны иметь разные правила. Один общий лимит создаёт случайные конфликты.

8) Проверьте X-Forwarded-For и real IP — за proxy или балансировщиком приложение может видеть IP самого proxy вместо IP клиента. Тогда все пользователи попадают в один bucket и быстро получают 429. В Nginx, ingress и приложении нужно корректно настроить доверенные proxy и извлечение реального IP.

9) Не поднимайте лимиты вслепую — если 429 защищает базу от перегрузки, простое увеличение лимита может заменить контролируемый отказ на 500, 502 или 504. Сначала проверьте saturation: CPU, пул соединений, очередь, latency, ошибки зависимостей.

В микросервисной архитектуре лимиты часто лучше держать не в каждом сервисе отдельно, а на входе: API Gateway, ingress или reverse proxy. Зачем нужен этот слой, разобрано в материале «Как работает API Gateway и зачем он нужен в микросервисах».

Мониторинг 429: когда это норма, а когда инцидент

Не каждый 429 — авария. На endpoint логина, регистрации, восстановления пароля и публичного поиска небольшое количество 429 может быть нормальной защитой. Но резкий рост или появление 429 на пользовательских сценариях — повод разбираться.

Смотрите минимум четыре группы сигналов.

1) Traffic — сколько всего запросов приходит, на какие маршруты, от каких клиентов. Рост 429 без роста общего трафика часто говорит о баге в лимитере или изменении правил.

2) Errors — доля 429 среди всех ответов и отдельно среди 4xx. Не смешивайте её с 5xx — это разные классы проблем.

3) Latency — перед 429 может расти задержка, если лимитер сначала ставит запросы в очередь или приложение упирается в зависимость.

4) Saturation — CPU, память, пул соединений, очередь задач, лимиты внешних API. Высокая saturation — 429 работает как полезный клапан; низкая — лимит, вероятно, слишком жёсткий или неправильно настроен.

Для HTTP API удобен RED-подход: rate, errors, duration. Подробнее — «Мониторинг HTTP API. RED-метрики, latency и error budget на практике».

Для публичного сайта полезен внешний мониторинг доступности: он покажет, видит ли проблему пользователь снаружи, а не только внутренние метрики. Например, Statuser проверяет сайт с заданным интервалом и присылает уведомление о сбое. Если проверка начала получать 429 вместо 200 — это повод проверить лимиты для публичных страниц, CDN/WAF и частоту самих проверок.

При настройке алертов не стоит будить команду из-за каждого единичного 429. Лучше заводить условия по доле ошибок, критичным маршрутам и длительности: «429 на /checkout больше порога 5 минут» полезнее, чем «любой 429 на любом endpoint».

FAQ

Почему появляется ошибка 429?
Сервер ограничил частоту запросов: по IP, пользователю, API-ключу, маршруту или общей квоте. Причиной может быть бот, баг во фронтенде, агрессивные ретраи, общий NAT или слишком жёсткая настройка лимитов.

Нужно ли просто обновить страницу при 429?
Один раз — можно. Но постоянное обновление только продлит блокировку. Лучше подождать время из Retry-After или снизить частоту действий.

429 влияет на SEO?
Если поисковый робот регулярно получает 429 на важных страницах, индексация может ухудшиться. Для ботов стоит задавать отдельные разумные лимиты и следить, чтобы публичные страницы не блокировались без причины.

Чем 429 отличается от блокировки IP?
429 обычно временный и связан с частотой запросов. Блокировка IP чаще возвращает 403, 401, 451 или вообще разрывает соединение. Но конкретное поведение зависит от WAF, CDN и настроек сервера.

Опубликовано 7 сентября 202610 минут чтенияМария Исаева
Средний рейтинг статьи — 4.8

Настроить мониторинг за 30 секунд

Надежные оповещения о даунтаймах. Без ложных срабатываний