频率限制


介绍

Laravel包含了一个简单的频率限制抽象,结合你的应用程序的缓存, 可以轻松地在指定的时间窗口内限制任何操作。

如果你对限制传入HTTP请求的费率有兴趣,请参阅频率限制中间件文档

缓存配置

通常,频率限制器使用你的应用程序默认的缓存,由你的应用程序的cache配置文件中的default键定义。然而,你可以通过在应用的cache配置文件中定义一个limiter键来指定频率限制器应使用哪个缓存驱动程序:

'default' => 'memcached',
'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,
);

手动增加尝试次数

如果你想手动地与频率限制器进行交互,还有其他一些方法可以用。例如,你可以调用tooManyAttempts方法以确定给定的频率限制键是否已经超过了其每分钟允许的最大尝试次数:

use Illuminate\Support\Facades\RateLimiter;

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

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

// 发送消息...

另外,你也可以使用remaining方法来检索给定键剩余的尝试次数。如果一个给定的键还有剩余的重试次数,你可以调用hit方法来增加尝试次数的总数:

use Illuminate\Support\Facades\RateLimiter;

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

    // 发送消息...
}

确定限制器的可用性

当一个键没有更多的尝试机会时,availableIn方法返回剩余的秒数,直到更多的尝试次数可用:

use Illuminate\Support\Facades\RateLimiter;

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

    return '你可以在 ' . $seconds. ' 秒后再尝试.';
}

RateLimiter::hit('send-message:' . $user->id);
  
// 发送消息...

清理尝试次数

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

Vote Vote Cancel Collect Collect Cancel

<< 上一篇: 队列

>> 下一篇: 任务调度