跳到主要內容

速率限制

📝 此頁面為 Laravel 官方文檔的繁體中文翻譯。查看原始英文版本

速率限制

簡介

Laravel 包含一個易於使用的速率限制抽象層,與應用程式的快取結合使用,提供了一種在指定時間窗口內限制任何操作的簡單方法。

[!NOTE] 如果您有興趣限制傳入的 HTTP 請求,請參閱速率限制器中介層文件

快取設定

通常,速率限制器使用預設的應用程式快取,由應用程式 cache 設定檔中的 default 鍵定義。但是,您可以透過在應用程式 cache 設定檔中定義 limiter 鍵來指定速率限制器應使用的快取驅動程式:

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

'limiter' => 'redis', // [tl! add]

基本用法

Illuminate\Support\Facades\RateLimiter facade 可用於與速率限制器互動。速率限制器提供的最簡單方法是 attempt 方法,它在給定的秒數內對給定的回呼進行速率限制。

當回呼沒有剩餘嘗試次數時,attempt 方法返回 false;否則,attempt 方法將返回回呼的結果或 true。第一個參數是速率限制器「索引鍵」,可以是您選擇的任何字串,代表正在被速率限制的操作:

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() {
        // Send message...
    },
    $decayRate = 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...

在限制可能同時收到許多請求的端點時,您可能希望檢查 increment 方法返回的值,而不是將 tooManyAttemptsincrement 作為單獨的操作使用。使用 redismemcacheddatabase 快取儲存時,此值會以原子方式遞增,確保每個並發請求都收到唯一的計數:

use Illuminate\Support\Facades\RateLimiter;

$perMinute = 5;

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

// 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...
}

如果您想將給定速率限制器索引鍵的值遞增超過一,可以向 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;

/**
 * Mark the message as read.
 */
public function read(Message $message): Message
{
    $message->markAsRead();

    RateLimiter::clear('send-message:'.$message->user_id);

    return $message;
}