При предоставлении API в общедоступную сеть для внешнего доступа к данным, во избежание злонамеренных атак, лучше всего добавить в API ограничение частоты запросов в дополнение к аутентификации по токену.В Laravel начиная с 5.2 компонент Throttle, который приходит с фреймворком поддерживает ограничение частоты доступа. , и предоставляет промежуточное ПО Throttle для использования, но промежуточное ПО Throttle будет возвращать HTML-ответ, когда частота доступа к API достигает предела, чтобы сообщить вам о необходимости разгона. В приложениях мы часто предпочитают возвращать ответ API вместо ответа HTML, поэтому в статье будет предоставлено специальное промежуточное ПО, которое заменит промежуточное ПО Throttle по умолчанию для реализации пользовательского содержимого ответа.
Обзор ограничения частоты
Ограничение частоты часто используется в API для ограничения частоты запросов к определенному API отдельными запросчиками. Например, если установлено ограничение частоты 1000 в минуту, при превышении лимита в течение минуты сервер вернет429: Too Many Attempts.отклик.
Как правило, хорошо написанное приложение, реализующее ограничение частоты, также возвращает три заголовка ответа:X-RateLimit-Limit, X-RateLimit-RemainingиRetry-After(Retry-Afterзаголовки будут возвращены только после достижения лимита).X-RateLimit-Limitсообщает нам максимальное количество запросов, разрешенных в указанное время,X-RateLimit-RemainingОтносится к количеству запросов, оставшихся в указанный период времени,Retry-AfterОтносится ко времени (с) ожидания до следующего запроса на повторную попытку.
Примечание: Каждое приложение будет выбирать свой собственный временной интервал ограничения частоты.Временной интервал ограничения частоты доступа приложения Laravel составляет одну минуту, поэтому ограничение частоты ограничивает количество посещений в одну минуту.
Используйте промежуточное программное обеспечение дросселя
Давайте посмотрим на использование этого промежуточного программного обеспечения.Сначала мы определяем маршрут и добавляем к нему дроссель промежуточного программного обеспечения.По умолчанию дроссель ограничивает 60 попыток в минуту и запрещает доступ после 60 посещений в минуту:
Route::group(['prefix'=>'api','middleware'=>'throttle'], function(){
Route::get('users', function(){
return \App\User::all();
});
});
При доступе к маршруту /api/users в заголовке ответа вы увидите следующую информацию:
X-RateLimit-Limit: 60 X-RateLimit-Remaining: 58
Если запрошен разгон, он будет возвращен в заголовке ответа.Retry-After:
Retry-After: 58 X-RateLimit-Limit: 60 X-RateLimit-Remaining: 0
Приведенная выше информация указывает на то, что доступ к странице или API вернется в нормальное состояние через 58 секунд.
Определите частоту и время ожидания повторных попыток
Частота по умолчанию – 60 раз. Вы можете указать желаемую частоту с помощью первого параметра промежуточного программного обеспечения дросселя. Время ожидания повторной попытки по умолчанию – одна минута. Вы можете указать желаемое количество минут с помощью второго параметра промежуточного программного обеспечения дросселирования.
Route::group(['prefix'=>'api','middleware'=>'throttle:5'],function(){
Route::get('users',function(){
return \App\User::all();
});
});//频次上限5
Route::group(['prefix'=>'api','middleware'=>'throttle:5,10'],function(){
Route::get('users',function(){
return \App\User::all();
});
});//频次上限5,重试等待时间10分钟
###Custom Throttle промежуточное ПО, возврат ответа API В дополнение к возврату этих заголовков ответа Throttle возвращает HTML-страницу, которая сообщает нам о слишком большом количестве попыток после того, как частота запросов достигает верхнего предела. При вызове API мы, очевидно, предпочитаем получать ответ в формате json.Ниже представлено пользовательское промежуточное ПО для замены промежуточного ПО Throttle по умолчанию для настройки информации ответа.
Сначала создайте промежуточное ПО ThrottleRequests:php artisan make:middleware ThrottleRequests.
Скопируйте приведенный ниже код вapp/Http/Middlewares/ThrottleReuqestsВ файле:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Cache\RateLimiter;
use Symfony\Component\HttpFoundation\Response;
class ThrottleRequests
{
/**
* 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_code' => 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);
}
}
потомapp/Http/Kernel.phpВ файле:
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
Заменить:
'throttle' => \App\Http\Middleware\ThrottleRequests::class,
Готово.
Информационный магазин дроссельной заслонки
Наконец, позвольте мне сказать,ThrottleЭти частотные данные хранятся вcacheвнутренний,Laravelдефолтcache driverдаfileэтоthrottleИнформация хранится по умолчанию вcacheфайл, если вашcache driverЕсли заменить его на redis, то информация будет храниться в redis.Записываемая информация на самом деле очень простая.ThrottleПодпись объекта запроса (хэш метода HTTP-запроса, доменного имени, URI и IP-адреса клиента) будет использоваться в качестве ключа кэша для записи количества клиентских запросов.