Skip to content
赞助商赞助商
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待

限流

介绍

Laravel 提供了一个简单易用的限流抽象,结合您应用程序的 缓存,提供了一种在指定时间窗口内限制任何操作的简单方法。

NOTE

如果您对限流传入的 HTTP 请求感兴趣,请查阅 限流中间件文档

缓存配置

通常,限流器利用您应用程序的默认缓存,如您应用程序的 cache 配置文件中的 default 键所定义。然而,您可以通过在应用程序的 cache 配置文件中定义 limiter 键来指定限流器应使用哪个缓存驱动:

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

'limiter' => 'redis',

基本用法

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

attempt 方法在回调没有剩余尝试时返回 false;否则,attempt 方法将返回回调的结果或 trueattempt 方法接受的第一个参数是限流器的“键”,可以是您选择的任何字符串,表示正在限流的操作:

php
use Illuminate\Support\Facades\RateLimiter;

$executed = RateLimiter::attempt(
    'send-message:'.$user->id,
    $perMinute = 5,
    function() {
        // 发送消息...
    }
);

if (! $executed) {
  return '发送的消息过多!';
}

如果需要,您可以向 attempt 方法提供第四个参数,即“衰减率”,或可用尝试重置的秒数。例如,我们可以修改上面的示例,以允许每两分钟五次尝试:

php
$executed = RateLimiter::attempt(
    'send-message:'.$user->id,
    $perTwoMinutes = 5,
    function() {
        // 发送消息...
    },
    $decayRate = 120,
);

手动增加尝试次数

如果您希望手动与限流器交互,可以使用多种其他方法。例如,您可以调用 tooManyAttempts 方法来确定给定的限流器键是否超过了每分钟允许的最大尝试次数:

php
use Illuminate\Support\Facades\RateLimiter;

if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) {
    return '尝试次数过多!';
}

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

// 发送消息...

或者,您可以使用 remaining 方法来检索给定键的剩余尝试次数。如果给定键还有剩余重试次数,您可以调用 increment 方法来增加总尝试次数:

php
use Illuminate\Support\Facades\RateLimiter;

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

    // 发送消息...
}

如果您希望将给定限流器键的值增加超过一个,您可以向 increment 方法提供所需的数量:

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

确定限流器可用性

当一个键没有更多的尝试时,availableIn 方法返回在更多尝试可用之前剩余的秒数:

php
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 方法重置给定限流器键的尝试次数。例如,当接收者阅读给定消息时,您可以重置尝试次数:

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