Гайды

Как добавить rate limiting — предохранитель от счёта на 10 000 запросов

Иллюстрация: поток запросов упирается в турникет, пропускающий по одному

Реальная страшилка вайб-кодера: модель написала тебе цикл, где-то ошиблась в условии выхода — и он ушёл дёргать платный API по кругу. Тысяча запросов в минуту, счёт растёт на глазах. Или бота нашёл скрипт-бот и долбит твой эндпоинт без остановки.

Лекарство одно и старое как мир — rate limiting, ограничение частоты запросов. Это предохранитель: «не больше N обращений за промежуток времени». Ниже — как добавить его руками, по шагам, без магии.

Шаг 1. Реши, что именно ограничиваешь

Прежде чем писать код, ответь на один вопрос: считать запросы по кому?

  • По IP — простейший вариант, защищает от «долбёжки» снаружи. Годится для публичной формы или открытого эндпоинта.
  • По пользователю — если у тебя есть вход, честнее считать по id пользователя: один человек с двух устройств не должен получать двойной лимит.
  • По API-ключу — если твой сервис дёргают другие программы.

Для первого приложения бери IP — это 90% пользы за 10% усилий.

Шаг 2. Выбери, где поставить турникет

Ограничитель ставят перед дорогой операцией. Два типичных места:

  • Перед своим эндпоинтом целиком — чтобы никто не завалил сервер.
  • Прямо вокруг вызова платной модели — чтобы даже свой же кривой код не сжёг бюджет. Это тот случай из вступления.

Часто нужно и то, и другое. Начни с эндпоинта.

Шаг 3. Самая простая версия — счётчик в памяти

Идея на пальцах: держим для каждого IP счётчик и время. Пришёл запрос — проверяем, не превышен ли лимит в окне.

const hits = new Map();               // ip -> { count, resetAt }
const LIMIT = 20;                     // 20 запросов
const WINDOW = 60_000;                // за 60 секунд

function rateLimit(ip) {
  const now = Date.now();
  const rec = hits.get(ip);
  if (!rec || now > rec.resetAt) {
    hits.set(ip, { count: 1, resetAt: now + WINDOW });
    return true;                      // пропускаем
  }
  if (rec.count >= LIMIT) return false; // блокируем
  rec.count++;
  return true;
}

В эндпоинте: if (!rateLimit(ip)) return res.status(429).send('Too many requests'). Двадцать строк — и грубый предохранитель готов.

Важно понимать его границу: счётчик живёт в памяти одного процесса. Перезапустил сервер — счётчики обнулились; серверов два — у каждого свой счёт. Для пет-проекта норм, для продакшена — шаг 5.

Шаг 4. Не изобретай — возьми библиотеку

Для реальных проектов есть готовые пакеты (что это такое — в статье про npm). На Node с Express — express-rate-limit, одна установка:

npm install express-rate-limit
import rateLimit from 'express-rate-limit';

app.use(rateLimit({ windowMs: 60_000, limit: 20 }));

Она сама считает по IP, сама шлёт правильный ответ и заголовки. Меньше кода — меньше багов.

Шаг 5. Для продакшена — общий счётчик

Как только серверов больше одного (а на бессерверном хостинге так почти всегда), счётчик нужно вынести наружу — в общее хранилище. Популярный простой вариант — Upstash (Redis по HTTP): все процессы смотрят в один счётчик, лимит становится честным. Настраивается это тоже пакетом, ключи держи в переменных окружения, а не в коде.

Шаг 6. Верни правильный ответ и проверь

Когда лимит превышен, отдавай код 429 Too Many Requests и, если можешь, заголовок Retry-After с числом секунд — по нему вежливый клиент поймёт, когда повторить. Не отдавай 200 с пустотой: клиент решит, что всё хорошо.

Проверить легко — быстро отправь много запросов подряд:

for i in $(seq 1 30); do curl -s -o /dev/null -w "%{http_code}\n" localhost:3000/api; done

Первые ответы — 200, после лимита пойдут 429. Значит, турникет работает.

Что получится

Публичный эндпоинт, который не завалить в лоб, и — главное — потолок на вызовы платной модели. Даже если завтра ИИ напишет тебе цикл с ошибкой, он упрётся в лимит, а не в твою карту. Дальше эту же привычку встраивай сразу, а не после первого страшного счёта — про экономию в целом есть отдельный разбор.

Rate limiting и защита от DDoS — это одно и то же?

Нет. Rate limiting режет частоту от одного источника и спасает от случайной «долбёжки» и мелких ботов. Настоящую распределённую атаку с тысяч адресов он не остановит — для этого есть уровень хостинга и CDN. Но 95% бытовых проблем закрывает именно он.

Где поставить лимит — на фронте или на бэкенде?

Только на бэкенде. Фронтенд легко обойти, отправив запрос напрямую. Ограничение должно жить там, где принимается решение выполнять операцию.

Rate limiting — из тех вещей, что кажутся «на потом», а спасают уже сегодня. Двадцать строк на старте дешевле одного счёта на пятизначную сумму. А собрать первое приложение с таким предохранителем проще в компании того, кто объясняет на «ты».

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение
Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →