速率限制

简介

Laravel 包含一个简单易用的速率限制抽象,它与应用程序的缓存结合使用,为在指定时间窗口内限制任何操作提供了简单的方法。

如果你对限制传入的 HTTP 请求感兴趣,请查阅速率限制中间件的文档。

缓存配置

通常,速率限制器使用你在应用程序的缓存配置文件中定义的默认应用缓存作为缓存驱动。不过,你可以通过在应用程序的缓存配置文件中定义一个 limiter 键来指定速率限制器应该使用哪个缓存驱动:

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

'limiter' => 'redis',

基本用法

Illuminate\Support\Facades\RateLimiter 门面可用于与速率限制器进行交互。速率限制器提供的最简单方法是 attempt 方法,该方法会对给定的回调进行速率限制,限制在指定的时间内的请求次数。

attempt 方法在回调没有剩余的尝试次数时返回 false;否则,attempt 方法将返回回调的结果或 trueattempt 方法的第一个参数是速率限制器的“键”,它可以是任何你选择的字符串,用来表示正在被速率限制的操作:

use Illuminate\Support\Facades\RateLimiter;

$executed = RateLimiter::attempt(
    'send-message:'.$user->id,  // 速率限制键
    $perMinute = 5,             // 每分钟最多尝试次数
    function() {
        // 发送消息...
    }
);

if (! $executed) {
  return '发送消息过于频繁!';
}

如果需要,你可以向 attempt 方法提供第四个参数,这个参数是“衰减速率”,即可用尝试次数重置之前的秒数。例如,我们可以修改上面的例子,以允许每两分钟最多进行五次尝试:

$executed = RateLimiter::attempt(
    'send-message:'.$user->id,  // 速率限制键
    $perTwoMinutes = 5,         // 每两分钟最多尝试次数
    function() {
        // 发送消息...
    },
    $decayRate = 120,           // 衰减速率:120秒(2分钟)
);

手动增加尝试次数

Illuminate\Support\Facades\RateLimiter 门面可以用来与速率限制器进行交互。速率限制器提供的最简单方法是 attempt 方法,该方法在指定的秒数内对给定的回调进行速率限制。

当回调没有剩余的尝试次数时,attempt 方法会返回 false;否则,attempt 方法将返回回调的结果或 trueattempt 方法接受的第一个参数是速率限制器的 "key",它可以是任何你选择的字符串,用来表示被限制的操作:

use Illuminate\Support\Facades\RateLimiter;

$executed = RateLimiter::attempt(
    'send-message:'.$user->id,  // 速率限制器的 key
    $perMinute = 5,  // 每分钟最多 5 次尝试
    function() {
        // 发送消息...
    }
);

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

如果需要,你可以为 attempt 方法提供第四个参数,即 "衰减率"(decay rate),即可用尝试次数重置之前的秒数。例如,我们可以修改上面的例子,每两分钟允许五次尝试:

$executed = RateLimiter::attempt(
    'send-message:'.$user->id,  // 速率限制器的 key
    $perTwoMinutes = 5,  // 每两分钟最多 5 次尝试
    function() {
        // 发送消息...
    },
    $decayRate = 120,  // 每两分钟重置一次
);

清除尝试次数

你可以使用 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;
}