Ограничение частоты запросов
Коротко: Метод ограничения того, как часто пользователь/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