Как исправить ошибку «429 Too Many Requests» в вашем веб-приложении
Ваше веб-приложение внезапно перестаёт работать. API-запросы завершаются с ошибкой. Пользователи видят сообщения об ошибках. Виновник? HTTP 429 Too Many Requests — способ сервера сообщить вашему приложению, что нужно замедлиться.
Это руководство объясняет, что вызывает ошибки 429 в современных веб-приложениях, как интерпретировать сигналы, которые отправляют серверы, и практические стратегии регулирования запросов на фронтенде, которые предотвращают возникновение этих ошибок.
Ключевые моменты
- HTTP 429 указывает на превышение лимита запросов — это сигнал замедлиться, а не сбой сервера.
- Используйте заголовки ограничения скорости (
X-RateLimit-*илиRateLimit) и заголовокRetry-Afterдля управления логикой повторных попыток. - Предотвращайте ошибки 429 с помощью debouncing, группировки запросов и агрессивного кэширования.
- Когда возникают ошибки 429, применяйте экспоненциальную задержку и ставьте повторные попытки в очередь вместо того, чтобы атаковать сервер.
Что на самом деле означает HTTP 429 Too Many Requests
Код состояния 429 указывает, что ваш клиент превысил лимиты скорости запросов, установленные сервером. В отличие от ошибок серии 500 (проблемы сервера) или 503 Service Unavailable (временная перегрузка), 429 однозначна: вы делаете слишком много запросов, и сервер защищает себя.
Ограничение скорости API может исходить из нескольких источников:
- Ваш собственный бэкенд, применяющий ограничения для каждого пользователя или сессии
- CDN и WAF, блокирующие паттерны трафика, которые выглядят подозрительно
- Сторонние API, защищающие свою инфраструктуру от чрезмерного количества вызовов
Каждый источник может иметь разные лимиты, разные окна обнаружения и разное поведение при восстановлении. Одно действие пользователя в вашем приложении может вызвать запросы к нескольким сервисам, любой из которых может вернуть 429.
Понимание заголовков ограничения скорости
Когда серверы реализуют ограничение скорости, они часто сообщают о лимитах через заголовки ответа. Существуют два паттерна:
Устаревшие заголовки используют префикс X-RateLimit-*:
X-RateLimit-Limit: Максимальное количество разрешённых запросовX-RateLimit-Remaining: Оставшиеся запросы в текущем окнеX-RateLimit-Reset: Когда лимит сбросится (обычно Unix timestamp)
Стандартизированные заголовки следуют более новому формату RateLimit и RateLimit-Policy, который предоставляет аналогичную информацию с лучше определённой семантикой.
Не каждый API использует эти заголовки. Некоторые возвращают только статус 429 без дополнительного контекста. Ваш код должен обрабатывать оба сценария.
Заголовок Retry-After
Заголовок Retry-After сообщает клиентам, когда они могут безопасно повторить попытку. Он появляется в двух форматах:
Retry-After: 120 // секунды ожидания
Retry-After: Wed, 21 Oct 2025 07:28:00 GMT // конкретная временная метка
Когда он присутствует, соблюдайте его. Когда отсутствует, реализуйте экспоненциальную задержку — ждите всё дольше между попытками (1 секунда, затем 2, затем 4 и так далее).
Некоторые серверы полностью опускают Retry-After. Другие включают его непоследовательно. Создавайте логику повторных попыток так, чтобы она работала без него, но учитывала его, когда он доступен.
Discover how at OpenReplay.com.
Стратегии регулирования запросов на фронтенде
Большинство ошибок 429 в приложениях с активным фронтендом возникает из-за взаимодействия с UI, вызывающего чрезмерное количество API-вызовов. Вот как их предотвратить:
Debouncing пользовательского ввода
Поля поиска, автодополнение и фильтры часто отправляют запросы при каждом нажатии клавиши. Debouncing ждёт, пока пользователь не прекратит печатать, прежде чем отправить запрос:
function debounce(func, delay) {
let timeoutId;
return function (...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
// Ждём 300 мс после последнего нажатия клавиши перед поиском
const debouncedSearch = debounce(searchAPI, 300);
Группировка связанных запросов
Вместо того чтобы получать данные для каждого элемента по отдельности, объединяйте запросы там, где API это поддерживает. Один запрос на 50 элементов лучше, чем 50 отдельных запросов.
Агрессивное кэширование
Сохраняйте ответы, которые не меняются часто. Перед выполнением запроса проверьте, есть ли у вас уже действительные кэшированные данные. Это относится как к кэшам браузера, так и к кэшированию на уровне приложения.
Соблюдение сигналов ограничения скорости
Когда вы получаете заголовки ограничения скорости, используйте их проактивно. Если X-RateLimit-Remaining показывает, что вы почти исчерпали лимит, замедлитесь до того, как достигнете предела.
Корректная обработка ошибок 429
Когда возникает 429, несмотря на усилия по предотвращению:
- Разберите ответ на наличие
Retry-Afterили заголовков ограничения скорости - Поставьте неудавшийся запрос в очередь для повторной попытки после указанной задержки
- Информируйте пользователей соответствующим образом — показывайте состояние загрузки, а не ошибку
- Логируйте происшествие, чтобы выявить паттерны в вашем мониторинге
Избегайте немедленных повторных попыток. Атака сервера, который только что сказал вам замедлиться, усугубляет ситуацию и может вызвать более длительные блокировки.
Обратите внимание, что некоторые CDN и WAF применяют фиксированные окна охлаждения, что означает, что повторные попытки могут быть заблокированы на минуты независимо от логики задержки на стороне клиента.
Отличие 429 от других ошибок
429 требует ожидания. 503 может разрешиться быстро или указывать на более серьёзный сбой. 500 предполагает баг. Ваша обработка ошибок должна различать:
- 429: Отступите, подождите, повторите попытку с указанной задержкой
- 503: Повторите попытку с задержкой, но отслеживайте продолжительные сбои
- 500: Залогируйте ошибку, возможно, повторите попытку один раз, затем корректно завершите с ошибкой
Заключение
HTTP 429 Too Many Requests — это сигнал ограничения скорости, а не сбой. Предотвращайте его через регулирование запросов на фронтенде — debouncing, группировку и кэширование. Когда это происходит, соблюдайте заголовок Retry-After и реализуйте экспоненциальную задержку.
Лучшее решение для ошибок 429 — никогда их не вызывать. Проектируйте своё приложение так, чтобы делать только необходимые запросы, и вы редко увидите эту ошибку в продакшене.
Часто задаваемые вопросы
Debouncing ждёт, пока активность не прекратится, прежде чем выполнить функцию, идеально подходит для полей поиска, где вам нужно конечное значение. Throttling ограничивает выполнение до одного раза за временной интервал, лучше подходит для событий прокрутки или непрерывных действий. Оба сокращают объём запросов, но debouncing обычно работает лучше для пользовательского ввода, который вызывает API-вызовы.
Начните с базовой задержки, например, 1 секунда, затем удваивайте её с каждой попыткой повтора. Добавьте случайный jitter, чтобы предотвратить синхронизированные повторные попытки от нескольких клиентов. Ограничьте максимальную задержку, чтобы избежать чрезмерного ожидания. Типичная последовательность может быть 1с, 2с, 4с, 8с, затем остановка после 4-5 попыток.
Да. Сторонние API могут иметь строгие лимиты для каждого ключа независимо от вашего общего трафика. Общие IP-адреса на облачных платформах могут вызывать лимиты CDN. Всплески паттернов от загрузки страниц или монтирования компонентов также могут превысить лимиты даже при небольшом общем количестве пользователей.
Обычно нет. Поскольку ошибки 429 временные и восстановимые, показывайте состояние загрузки во время повторных попыток в фоновом режиме. Отображайте ошибку только если повторные попытки исчерпаны. Пользователям не нужно знать об ограничении скорости — они просто хотят, чтобы их действие завершилось.
Understand every bug
Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.