Skip to content

レートリミット

はじめに

Laravelには、アプリケーションのキャッシュと組み合わせて、指定された時間枠内で任意のアクションを制限する簡単な方法を提供する、使いやすいレートリミットの抽象化が含まれています。

Note

受信HTTPリクエストのレートリミットに興味がある場合は、レートリミッターミドルウェアのドキュメントを参照してください。

キャッシュ設定

通常、レートリミッターは、アプリケーションのcache設定ファイル内のdefaultキーで定義されたデフォルトのアプリケーションキャッシュを利用します。ただし、アプリケーションのcache設定ファイル内にlimiterキーを定義することで、レートリミッターが使用するキャッシュドライバーを指定できます。

'default' => env('CACHE_STORE', 'database'),

'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() {
        // メッセージを送信...
    }
);

if (! $executed) {
  return 'メッセージ送信回数が多すぎます!';
}

必要に応じて、attemptメソッドに4番目の引数を提供できます。これは「減衰率」、つまり利用可能な試行回数がリセットされるまでの秒数です。たとえば、上記の例を修正して、2分ごとに5回の試行を許可するようにできます。

$executed = RateLimiter::attempt(
    'send-message:'.$user->id,
    $perTwoMinutes = 5,
    function() {
        // メッセージを送信...
    },
    $decayRate = 120,
);

手動での試行回数増加

レートリミッターと手動でやり取りしたい場合、他にもさまざまなメソッドが利用できます。たとえば、tooManyAttemptsメソッドを呼び出して、指定されたレートリミッターキーが1分あたりの最大許容試行回数を超えたかどうかを判断できます。

use Illuminate\Support\Facades\RateLimiter;

if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) {
    return '試行回数が多すぎます!';
}

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

// メッセージを送信...

あるいは、remainingメソッドを使用して、指定されたキーに残っている試行回数を取得できます。指定されたキーに残りの試行回数がある場合、incrementメソッドを呼び出して試行回数の合計を増やすことができます。

use Illuminate\Support\Facades\RateLimiter;

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

    // メッセージを送信...
}

指定されたレートリミッターキーの値を1より大きく増やしたい場合は、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 $seconds.'秒後に再試行できます。';
}

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

// メッセージを送信...

試行回数のクリア

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;
}

ユーザーノート