Представьте, что ваше приложение работает стабильно и быстро до тех пор, пока внезапный поток запросов не начинает валиться на сервер со всех сторон. Часть из них от реальных пользователей, а часть от ботов или злоумышленников, которые обновляют страницы снова и снова. Без контроля такие потоки способны значительно замедлить работу приложения или даже привести к его падению.
В Laravel встроена система ограничения частоты запросов (rate limiting), которая защищает приложение от перегрузки, спама и злоупотреблений. Эта статья объясняет, что такое rate limiting, почему это важно и как гибко применять его в ваших проектах.
Что такое rate limiting и зачем он нужен
Rate limiting - это механизм, который ограничивает, сколько раз можно выполнить определённое действие за фиксированный промежуток времени. Проще говоря, это ограничитель скорости для запросов к вашему приложению.
Это помогает:
Предотвратить перегрузку сервера при наплыве запросов.
Стабилизировать работу API и ускорить ответы.
Защитить от автоматизированных атак, ботов и грубой силы (brute-force).
Обеспечить справедливый доступ к ресурсам для всех пользователей.
Экономить ресурсы сервера и снизить расходы на инфраструктуру.
Защитить чувствительные маршруты (например, логин или регистрацию) от злоупотреблений.
Встроенный rate limiting в Laravel (рекомендуемый способ)
Laravel предлагает мощный и простой способ настройки ограничений через фасад RateLimiter::for(). Это позволяет определять именованные лимитеры, которые затем применяются через middleware.
Вот пример, который ограничивает отправку логинов с одного IP-адреса:
// Файл: App\Providers\AppServiceProvider.php
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
public function boot(): void
{
RateLimiter::for('login', function (Request $request) {
return Limit::perMinute(5)
->by($request->ip())
->response(function () {
return response()->json([
'message' => 'Слишком много попыток. Повторите позже.'
], 429);
});
});
}Теперь вы можете применить этот лимитер к маршруту:
Route::middleware('throttle:login')->post('/login', [AuthController::class, 'login']);В этом примере:
Пользователь может попытаться выполнить логин не более 5 раз в минуту.
Если лимит превышен, будет возвращён ответ с кодом 429 Too Many Requests и кастомным сообщением.
Стратегии применения rate limiting
Rate limiting можно адаптировать под разные сценарии. Ниже приведены четырёх примера паттернов, которые помогают защитить приложение в разных случаях.
1. Ограничение по роли пользователя
В SaaS-приложениях разные группы пользователей могут иметь разные уровни доступа. Например:
Администраторы - много запросов,
Платные пользователи - среднее количество,
Бесплатные пользователи - меньше запросов,
Гости - минимальное количество.
Пример middleware:
public function handle(Request $request, Closure $next){
$role = $request->user()?->role ?? 'guest';
$limits = ['admin' => 100, 'premium' => 200, 'free' => 60, 'guest' => 20];
$maxAttempts = $limits[$role] ?? 20;
$key = "rate:{$role}:" . ($request->user()?->id ?? $request->ip());
if (RateLimiter::tooManyAttempts($key, $maxAttempts)) {
return response()->json(['message' => 'Слишком много запросов.'], 429);
}
RateLimiter::hit($key, 60);
return $next($request);
}Такой подход полезен, когда разные группы пользователей должны иметь разные лимиты.
2. Ограничение по IP
Иногда нужно ограничить поведение по IP-адресу. Например, если один и тот же адрес слишком часто вызывает API-эндпоинт.
Пример:
public function handle(Request $request, Closure $next)
{
$ip = $request->ip();
$key = 'rate_limit:ip:' . $ip;
if (RateLimiter::tooManyAttempts($key, 60)) {
return response()->json(['message' => 'Слишком много запросов с вашего IP.'], 429);
}
RateLimiter::hit($key, 60);
return $next($request);
}Это удобно для анонимных маршрутов или API-вызовов без авторизации.
3. Мягкое ограничение всплесков трафика
Во время всплесков нагрузки (например, распродаж или акций) вы можете не запрещать запросы жёстко, а предоставить пользователям возможность "спокойно подождать" или получать упрощённые ответы.
Пример такого middleware:
public function handle(Request $request, Closure $next)
{
$key = 'burst:' . $request->ip();
if (RateLimiter::tooManyAttempts($key, 30)) {
return response()->json(['message' => 'Слишком много запросов — попробуйте чуть позже'], 429);
}
RateLimiter::hit($key, 30);
return $next($request);
}Это даёт гибкий контроль над всплесками нагрузки.
4. Ограничение на основе API-токенов
Если ваше приложение предоставляет API с ключами доступа (API токенами), можно ограничивать запросы в зависимости от типа токена:
public function handle(Request $request, Closure $next)
{
$token = $request->bearerToken();
$key = 'rate_limit:token:' . ($token ?? $request->ip());
if (RateLimiter::tooManyAttempts($key, 100)) {
return response()->json(['message' => 'Превышен лимит запросов'], 429);
}
RateLimiter::hit($key, 60);
return $next($request);
}Это особенно полезно, если у вас есть платные и бесплатные API-ключи с разными квотами.
Регистрация middleware
Когда вы создали свои rate limiting middleware, их нужно зарегистрировать в приложении:
// В Kernel.php
protected $routeMiddleware = [
'role.throttle' => RateLimitByRole::class,
'ip.throttle' => RateLimitByIP::class,
'burst.throttle' => BurstLimit::class,
'token.throttle' => RateLimitByToken::class,
];После этого их можно применять к маршрутам, как обычные middleware.
Rate limiting - это не просто защита от злоумышленников. Это важная часть архитектуры высоконагруженного приложения, которая помогает:
Поддерживать скорость и стабильность API.
Снизить избыточную нагрузку на сервер.
Обеспечить справедливый доступ для всех пользователей.
Защитить чувствительные маршруты от атак типа brute-force и DDoS.
Laravel предоставляет мощные и гибкие инструменты для реализации rate limiting. Начните с простых настроек через RateLimiter::for() и постепенно адаптируйте стратегию под нужды вашего проекта.