Любите загадки? Событие еще доступно на сайте.
Примите наш вызов и улучшите свои навыки!
Примите наш вызов и улучшите свои навыки!

Ограничение скорости

Введение

Laravel включает простую в использовании абстракцию ограничения скорости, которая в сочетании с кешем вашего приложения обеспечивает простой способ ограничить любое действие в течение указанного периода времени.

Если вас интересует ограничение скорости входящих HTTP-запросов, обратитесь к документации посредника для ограничения частоты запросов.

Конфигурация кеша

Обычно ограничитель скорости использует кеш вашего приложения по умолчанию, как определено ключом default в файле конфигурации cache вашего приложения. Однако вы можете указать, какой драйвер кеша должен использовать ограничитель скорости, задав ключ limiter в файле конфигурации cache вашего приложения:

'default' => 'memcached',

'limiter' => 'redis',

Базовое использование

Фасад Illuminate\Support\Facades\RateLimiter может использоваться для взаимодействия с ограничителем скорости. Самый простой метод, предлагаемый ограничителем скорости – это метод attempt который ограничивает скорость данного обратного вызова на заданное количество секунд.

Метод attempt возвращает false если для обратного вызова не осталось доступных попыток; в противном случае метод attempt вернет результат обратного вызова или true. Первым аргументом, принимаемым методом attempt является «ключ» ограничителя скорости, который может быть любой строкой по вашему выбору, представляющей действие с ограничением скорости:

use Illuminate\Support\Facades\RateLimiter;

$executed = RateLimiter::attempt(
    'send-message:'.$user->id,
    $perMinute = 5,
    function() {
        // Send message...
    }
);

if (! $executed) {
  return 'Too many messages sent!';
}

При необходимости, вы можете добавить четвёртый аргумент к методу attempt, который представляет собой “скорость сброса”, или количество секунд до обновления количества доступных попыток. К примеру, мы можем изменить вышеуказанный пример так, чтобы разрешить пять попыток каждые две минуты:

$executed = RateLimiter::attempt(
    'send-message:'.$user->id,
    $perTwoMinutes = 5,
    function() {
        // Отправить сообщение...
    },
    $decaySeconds = 120
);

Ручное увеличение числа попыток

Если вы хотите вручную взаимодействовать с ограничителем скорости, доступно множество других методов. Например, вы можете вызвать метод tooManyAttempts, чтобы определить, не превысил ли заданный ключ ограничителя скорости максимальное количество разрешенных попыток в минуту:

use Illuminate\Support\Facades\RateLimiter;

if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) {
    return 'Too many attempts!';
}

RateLimiter::increment('send-message:'.$user->id);

// Send message...

В качестве альтернативы вы можете использовать метод remaining для получения количества попыток, оставшихся для данного ключа. Если для данного ключа остались повторные попытки, вы можете вызвать метод increment, чтобы увеличить общее количество попыток:

use Illuminate\Support\Facades\RateLimiter;

if (RateLimiter::remaining('send-message:'.$user->id, $perMinute = 5)) {
    RateLimiter::increment('send-message:'.$user->id);

    // Send message...
}

RateLimiter::increment('send-message:'.$user->id);

// Send message...

Если вы хотите увеличить значение для определенного ключа более чем на единицу, вы можете указать желаемое число для метода increment:

RateLimiter::increment('send-message:'.$user->id, amount: 5);

Определение доступности ограничителя скорости

Когда у ключа больше не осталось попыток, метод availableIn возвращает количество секунд, оставшихся до тех пор, пока не будут доступны новые попытки:

use Illuminate\Support\Facades\RateLimiter;

if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) {
    $seconds = RateLimiter::availableIn('send-message:'.$user->id);

    return 'You may try again in '.$seconds.' seconds.';
}

RateLimiter::increment('send-message:'.$user->id);

// Send message...

Очистка счетчика попыток

Вы можете сбросить количество попыток для данного ключа ограничителя скорости, используя метод clear. Например, вы можете сбросить количество попыток, когда данное сообщение прочитано получателем:

use App\Models\Message;
use Illuminate\Support\Facades\RateLimiter;

/**
 * Отметьте сообщение как прочитанное.
 */
public function read(Message $message): Message
{
    $message->markAsRead();
    
    RateLimiter::clear('send-message:'.$message->user_id);
    
    return $message;
}