При предоставлении 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-адреса клиента) будет использоваться в качестве ключа кэша для записи количества клиентских запросов.