跳轉至內容

速率限制

簡介

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

如果您對限制傳入 HTTP 請求的速率感興趣,請查閱 速率限制器中介軟體文件

快取配置

通常,速率限制器會使用應用程式 cache 配置檔案中 default 鍵定義的預設快取。不過,您也可以透過在 cache 配置檔案中定義 limiter 鍵,來指定速率限制器應使用的快取驅動。

1'default' => env('CACHE_STORE', 'database'),
2 
3'limiter' => 'redis',

基本用法

可以使用 Illuminate\Support\Facades\RateLimiter 門面(facade)與速率限制器進行互動。速率限制器提供的最簡單方法是 attempt 方法,它會在給定的秒數內對指定的閉包進行速率限制。

當閉包沒有剩餘嘗試次數時,attempt 方法會返回 false;否則,attempt 方法將返回閉包的結果或 trueattempt 方法接受的第一個引數是速率限制器的“鍵”(key),這可以是您選擇的任何字串,代表正在進行速率限制的操作。

1use Illuminate\Support\Facades\RateLimiter;
2 
3$executed = RateLimiter::attempt(
4 'send-message:'.$user->id,
5 $perMinute = 5,
6 function() {
7 // Send message...
8 }
9);
10 
11if (! $executed) {
12 return 'Too many messages sent!';
13}

如有必要,您可以為 attempt 方法提供第四個引數,即“衰減率”(decay rate),即重置可用嘗試次數所需的秒數。例如,我們可以修改上面的示例,改為每兩分鐘允許嘗試五次。

1$executed = RateLimiter::attempt(
2 'send-message:'.$user->id,
3 $perTwoMinutes = 5,
4 function() {
5 // Send message...
6 },
7 $decayRate = 120,
8);

手動增加嘗試次數

如果您想手動與速率限制器互動,還可以使用多種其他方法。例如,您可以呼叫 tooManyAttempts 方法來確定給定的速率限制器鍵是否已超過每分鐘允許的最大嘗試次數。

1use Illuminate\Support\Facades\RateLimiter;
2 
3if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) {
4 return 'Too many attempts!';
5}
6 
7RateLimiter::increment('send-message:'.$user->id);
8 
9// Send message...

或者,您可以使用 remaining 方法來獲取給定鍵的剩餘嘗試次數。如果給定鍵還有剩餘重試次數,您可以呼叫 increment 方法來增加總嘗試次數。

1use Illuminate\Support\Facades\RateLimiter;
2 
3if (RateLimiter::remaining('send-message:'.$user->id, $perMinute = 5)) {
4 RateLimiter::increment('send-message:'.$user->id);
5 
6 // Send message...
7}

如果您希望將給定速率限制器鍵的值增加超過 1 的數值,可以將所需的數值傳遞給 increment 方法。

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

確定限制器可用性

當某個鍵沒有剩餘嘗試次數時,availableIn 方法會返回距離下一次可用嘗試所需的剩餘秒數。

1use Illuminate\Support\Facades\RateLimiter;
2 
3if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) {
4 $seconds = RateLimiter::availableIn('send-message:'.$user->id);
5 
6 return 'You may try again in '.$seconds.' seconds.';
7}
8 
9RateLimiter::increment('send-message:'.$user->id);
10 
11// Send message...

清除嘗試次數

您可以使用 clear 方法重置給定速率限制器鍵的嘗試次數。例如,當接收者讀取給定訊息時,您可以重置嘗試次數。

1use App\Models\Message;
2use Illuminate\Support\Facades\RateLimiter;
3 
4/**
5 * Mark the message as read.
6 */
7public function read(Message $message): Message
8{
9 $message->markAsRead();
10 
11 RateLimiter::clear('send-message:'.$message->user_id);
12 
13 return $message;
14}