EMZETT.
Войти

Ограничение частоты запросов

Коротко: Метод ограничения того, как часто пользователь/IP-адрес может делать запросы за период времени — защищает от злоупотреблений (например, перебора при входе, спама) и перегрузки.

Подробнее: Часто реализуется через быстрый кэш вроде Redis (счётчик на пользователя/IP со сроком действия). Если ограничение применяется к КАЖДОМУ запросу (включая безобидные страницы только для чтения), каждый просмотр страницы стоит дополнительного сетевого обращения туда и обратно — это заметно во времени загрузки.

Наш контекст: В Emzett сначала работало глобально на каждом запросе; затем его ограничили так, чтобы чисто читаемые страницы GET/HEAD без форм были исключены (вход, оформление заказа, чат и администрирование остаются полностью защищёнными), чтобы сэкономить время загрузки и нагрузку на Redis.

Подробности

Самый распространённый метод ограничения — «скользящее окно»: вместо простого подсчёта «сколько запросов с последней полной минуты» рассматривается скользящее временное окно (например, «сколько запросов за последние 60 секунд, считая от сейчас») — это не даёт использовать полный лимит непосредственно перед границей минуты и сразу после неё и тем самым фактически пропустить вдвое больше запросов, чем разрешено. Библиотеки вроде @upstash/ratelimit реализуют это бессерверно через Redis, без необходимости самим писать логику временных окон:

const ratelimit = new Ratelimit({
  redis,
  limiter: Ratelimit.slidingWindow(100, "1 m"), // 100 запросов в минуту
});
const { success } = await ratelimit.limit(`edge:${ip}`);
if (!success) {
  return new Response("Too many requests", { status: 429 });
}

Важно, КАКОЙ идентификатор используется для подсчёта: простой IP-адрес прост, но проблематичен за общими NAT/корпоративными сетями (много реальных пользователей делят один видимый IP) и легко обходится ротацией IP; комбинация IP + учётная запись пользователя (где доступна) точнее. В глобально распределённых edge-средах (таких как Vercel Edge Functions) само хранилище счётчиков тоже должно быть глобально согласованным — локальный счётчик в памяти на каждый экземпляр сервера фактически умножал бы лимит при параллельной работе нескольких экземпляров, поэтому нужно центральное хранилище вроде Redis.

См. также: Upstash Redis