- How to customize Laravel throttle message response
- Ограничение скорости запросов API в Laravel 5.2
- Краткое введение в ограничение скорости запросов
- Как использовать посредник для ограничения скорости запросов Laravel
- Настройка посредника throttle
- Комментарии (2)
- How to customize Laravel throttle message response
How to customize Laravel throttle message response
When you are using laravel api, then you must use throttling to protect your api from scrapping or any other attack. When you are limiting your api using laravel throttle then you get a html response message containing «Too Many Attempts.»
In order to change the message in a custom format and json reponse follow the steps below:
Create a new file ThrottleRequestsMiddleware.php in app/Http/Middleware/ and paste the code below:
namespace App\Http\Middleware; use Closure; use Illuminate\Cache\RateLimiter; use Symfony\Component\HttpFoundation\Response; class ThrottleRequestsMiddleware < /** * The rate limiter instance. * * @var \Illuminate\Cache\RateLimiter */ protected $limiter; /** * Create a new request throttler. * * @param \Illuminate\Cache\RateLimiter $limiter */ public function __construct(RateLimiter $limiter) < $this->limiter = $limiter; > /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @param int $maxAttempts * @param int $decayMinutes * @return mixed */ public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1) < $key = $this->resolveRequestSignature($request); if ($this->limiter->tooManyAttempts($key, $maxAttempts, $decayMinutes)) < return $this->buildResponse($key, $maxAttempts); > $this->limiter->hit($key, $decayMinutes); $response = $next($request); return $this->addHeaders( $response, $maxAttempts, $this->calculateRemainingAttempts($key, $maxAttempts) ); > /** * Resolve request signature. * * @param \Illuminate\Http\Request $request * @return string */ protected function resolveRequestSignature($request) < return $request->fingerprint(); > /** * Create a 'too many attempts' response. * * @param string $key * @param int $maxAttempts * @return \Illuminate\Http\Response */ protected function buildResponse($key, $maxAttempts) < $message = json_encode([ 'error' => [ 'message' => 'Too many attempts, please slow down the request.' //may comes from lang file ], 'status' => 4029 //your custom code ]); $response = new Response($message, 429); $retryAfter = $this->limiter->availableIn($key); return $this->addHeaders( $response, $maxAttempts, $this->calculateRemainingAttempts($key, $maxAttempts, $retryAfter), $retryAfter ); > /** * Add the limit header information to the given response. * * @param \Symfony\Component\HttpFoundation\Response $response * @param int $maxAttempts * @param int $remainingAttempts * @param int|null $retryAfter * @return \Illuminate\Http\Response */ protected function addHeaders(Response $response, $maxAttempts, $remainingAttempts, $retryAfter = null) < $headers = [ 'X-RateLimit-Limit' => $maxAttempts, 'X-RateLimit-Remaining' => $remainingAttempts, ]; if (!is_null($retryAfter)) < $headers['Retry-After'] = $retryAfter; $headers['Content-Type'] = 'application/json'; > $response->headers->add($headers); return $response; > /** * Calculate the number of remaining attempts. * * @param string $key * @param int $maxAttempts * @param int|null $retryAfter * @return int */ protected function calculateRemainingAttempts($key, $maxAttempts, $retryAfter = null) < if (!is_null($retryAfter)) < return 0; > return $this->limiter->retriesLeft($key, $maxAttempts); > >
Then go to your kernel.php file in app/Http/ directory and replace
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'throttle' => \App\Middleware\ThrottleRequestsMiddleware::class,
Note: You an extend the base ThrottleRequests class and override the responsible methods, but I am lazy to do that rather I like to copy-paste.
Ограничение скорости запросов API в Laravel 5.2
В последнее время я всё чаще и чаще работаю над созданием API при разработке на Laravel. Я использую свой класс для ручного ограничения скорости запросов, но мне всегда казалось, что для этого есть более простое решение. И не удивительно, что когда Тэйлор собрался написать посредник для ограничения скорости запросов, то у него это вышло проще и лучше, чем у меня.
Это одна из статей о новых функциях Laravel 5.2. Скоро будут ещё, не пропустите.
Краткое введение в ограничение скорости запросов
Если вы ещё не знакомы с ним, то ограничение скорости — это часто используемый в API инструмент, который ограничивает скорость запросов для каждого отдельного запрашивающего.
Это означает, например, если какой-нибудь бот обращается к довольно затратному API-маршруту тысячу раз в минуту, ваше приложение не упадёт, потому что после n-й попытки он получит от сервера ответ 429: Too Many Attempts (слишком много попыток).
Обычно хорошо написанное приложение, использующее ограничение скорости, в отличие от других приложений будет также возвращать три заголовка: X-RateLimit-Limit , X-RateLimit-Remaining и Retry-After (если вы достигните предела, то получите только Retry-After ). X-RateLimit-Limit — это максимальное число запросов для приложения, разрешённое в данном интервале времени. X-RateLimit-Remaining — это сколько запросов у вас осталось в данном интервале времени. А Retry-After — это сколько секунд надо ждать до следующей попытки. ( Retry-After может быть не количеством секунд, а датой).
Каждый API выбирает свой интервал времени для ограничения. У GitHub он равен часу, у Twitter — 15 минут. У данного посредника Laravel — 1 минута.
Как использовать посредник для ограничения скорости запросов Laravel
Рассмотрим новую возможность Laravel 5.2. Появился новый посредник throttle . Посмотрим на нашу группу API:
Route::group(['prefix' => 'api'], function () Route::get('people', function () return Person::all();
>);
>);
Применим к ней throttle . По умолчанию его предел — 60 попыток в минуту, ограничение длится в течение той минуты, когда достигнут предел.
Route::group(['prefix' => 'api', 'middleware' => 'throttle'], function () Route::get('people', function () return Person::all();
>);
>);
Теперь при запросе к этому маршруту api/people вы увидите такие строчки в заголовках ответов:
HTTP/1.1 200 OK . other headers here . X-RateLimit-Limit: 60 X-RateLimit-Remaining: 59
Запомните, этот ответ значит:
а) этот запрос успешный (статус 200)
б) вы можете обращаться к этому маршруту со скоростью 60 раз в минуту
в) у вас осталось 59 запросов в этой минуте
Какой ответ мы получим, если достигнем предела:
HTTP/1.1 429 Too Many Requests . other headers here . Retry-After: 60 X-RateLimit-Limit: 60 X-RateLimit-Remaining: 0
И содержимым ответа будет строка: Too Many Attempts. (слишком много попыток).
А если попробовать через 30 секунд?
HTTP/1.1 429 Too Many Requests . other headers here . Retry-After: 30
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
Тот же ответ, только таймер Retry-After , означающий сколько надо подождать, уже на отметке 30.
Настройка посредника throttle
Давайте немного настроим. Сделаем ограничение на 5 попыток в минуту.
Route::group(['prefix' => 'api', 'middleware' => 'throttle:5'], function () Route::get('people', function () return Person::all();
>);
>);
А теперь сделаем так, что если кто-то достигнет предела, то ему надо будет ждать 10 минут.
Route::group(['prefix' => 'api', 'middleware' => 'throttle:5,10'], function () Route::get('people', function () return Person::all();
>);
>);
Как вы считаете, полезен ли этот материал? Да Нет
Комментарии (2)
Ограничение скорости Laravel — отличная возможность в Laravel контролировать количество обращений.
А можно использовать 2 посредника, например первый throttle:5,1 а второй throttle:20,60 ?
Потому что пользователи часто чтото быстро делают за короткий промежуток времени потом отдыхают, потом опять чтото поделал и так несколько раз за большой промежуток времени. Надеюсь вы поняли о чём я.
Статистика: Символов — 3 957/3 325 без пробелов (2 628/2 222 без кода):, слов — 407
Наверх Опечатка? Выдели и нажми Ctrl+Enter (Orphus.ru)
How to customize Laravel throttle message response
When you are using laravel api, then you must use throttling to protect your api from scrapping or any other attack. When you are limiting your api using laravel throttle then you get a html response message containing «Too Many Attempts.»
In order to change the message in a custom format and json reponse follow the steps below:
Create a new file ThrottleRequestsMiddleware.php in app/Http/Middleware/ and paste the code below:
namespace App\Http\Middleware; use Closure; use Illuminate\Cache\RateLimiter; use Symfony\Component\HttpFoundation\Response; class ThrottleRequestsMiddleware < /** * The rate limiter instance. * * @var \Illuminate\Cache\RateLimiter */ protected $limiter; /** * Create a new request throttler. * * @param \Illuminate\Cache\RateLimiter $limiter */ public function __construct(RateLimiter $limiter) < $this->limiter = $limiter; > /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @param int $maxAttempts * @param int $decayMinutes * @return mixed */ public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1) < $key = $this->resolveRequestSignature($request); if ($this->limiter->tooManyAttempts($key, $maxAttempts, $decayMinutes)) < return $this->buildResponse($key, $maxAttempts); > $this->limiter->hit($key, $decayMinutes); $response = $next($request); return $this->addHeaders( $response, $maxAttempts, $this->calculateRemainingAttempts($key, $maxAttempts) ); > /** * Resolve request signature. * * @param \Illuminate\Http\Request $request * @return string */ protected function resolveRequestSignature($request) < return $request->fingerprint(); > /** * Create a 'too many attempts' response. * * @param string $key * @param int $maxAttempts * @return \Illuminate\Http\Response */ protected function buildResponse($key, $maxAttempts) < $message = json_encode([ 'error' => [ 'message' => 'Too many attempts, please slow down the request.' //may comes from lang file ], 'status' => 4029 //your custom code ]); $response = new Response($message, 429); $retryAfter = $this->limiter->availableIn($key); return $this->addHeaders( $response, $maxAttempts, $this->calculateRemainingAttempts($key, $maxAttempts, $retryAfter), $retryAfter ); > /** * Add the limit header information to the given response. * * @param \Symfony\Component\HttpFoundation\Response $response * @param int $maxAttempts * @param int $remainingAttempts * @param int|null $retryAfter * @return \Illuminate\Http\Response */ protected function addHeaders(Response $response, $maxAttempts, $remainingAttempts, $retryAfter = null) < $headers = [ 'X-RateLimit-Limit' => $maxAttempts, 'X-RateLimit-Remaining' => $remainingAttempts, ]; if (!is_null($retryAfter)) < $headers['Retry-After'] = $retryAfter; $headers['Content-Type'] = 'application/json'; > $response->headers->add($headers); return $response; > /** * Calculate the number of remaining attempts. * * @param string $key * @param int $maxAttempts * @param int|null $retryAfter * @return int */ protected function calculateRemainingAttempts($key, $maxAttempts, $retryAfter = null) < if (!is_null($retryAfter)) < return 0; > return $this->limiter->retriesLeft($key, $maxAttempts); > >
Then go to your kernel.php file in app/Http/ directory and replace
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'throttle' => \App\Middleware\ThrottleRequestsMiddleware::class,
Note: You an extend the base ThrottleRequests class and override the responsible methods, but I am lazy to do that rather I like to copy-paste.