跳转至内容

速率限制

简介

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}