6.8 KiB
Rate Limiting
- Introduction
- Cache Configuration
- Basic Usage
- Manually Incrementing Attempts
- Clearing Attempts
Introduction
Laravel includes a simple to use rate limiting abstraction which, in conjunction with your application's cache, provides an easy way to limit any action during a specified window of time.
If you are interested in rate limiting incoming HTTP requests, please consult the rate limiter middleware documentation.
Cache Configuration
Typically, the rate limiter utilizes your default application cache as defined
by the default key within your application's cache configuration file.
However, you may specify which cache driver the rate limiter should use by
defining a limiter key within your application's cache configuration file:
1'default' => env('CACHE_STORE', 'database'),
2
3'limiter' => 'redis',
'default' => env('CACHE_STORE', 'database'),
'limiter' => 'redis',
Basic Usage
The Illuminate\Support\Facades\RateLimiter facade may be used to interact
with the rate limiter. The simplest method offered by the rate limiter is the
attempt method, which rate limits a given callback for a given number of
seconds.
The attempt method returns false when the callback has no remaining
attempts available; otherwise, the attempt method will return the callback's
result or true. The first argument accepted by the attempt method is a
rate limiter "key", which may be any string of your choosing that represents
the action being rate limited:
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}
use Illuminate\Support\Facades\RateLimiter;
$executed = RateLimiter::attempt(
'send-message:'.$user->id,
$perMinute = 5,
function() {
// Send message...
}
);
if (! $executed) {
return 'Too many messages sent!';
}
If necessary, you may provide a fourth argument to the attempt method, which
is the "decay rate", or the number of seconds until the available attempts are
reset. For example, we can modify the example above to allow five attempts
every two minutes:
1$executed = RateLimiter::attempt(
2 'send-message:'.$user->id,
3 $perTwoMinutes = 5,
4 function() {
5 // Send message...
6 },
7 $decayRate = 120,
8);
$executed = RateLimiter::attempt(
'send-message:'.$user->id,
$perTwoMinutes = 5,
function() {
// Send message...
},
$decayRate = 120,
);
Manually Incrementing Attempts
If you would like to manually interact with the rate limiter, a variety of
other methods are available. For example, you may invoke the tooManyAttempts
method to determine if a given rate limiter key has exceeded its maximum
number of allowed attempts per minute:
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...
use Illuminate\Support\Facades\RateLimiter;
if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) {
return 'Too many attempts!';
}
RateLimiter::increment('send-message:'.$user->id);
// Send message...
Alternatively, you may use the remaining method to retrieve the number of
attempts remaining for a given key. If a given key has retries remaining, you
may invoke the increment method to increment the number of total attempts:
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}
use Illuminate\Support\Facades\RateLimiter;
if (RateLimiter::remaining('send-message:'.$user->id, $perMinute = 5)) {
RateLimiter::increment('send-message:'.$user->id);
// Send message...
}
If you would like to increment the value for a given rate limiter key by more
than one, you may provide the desired amount to the increment method:
1RateLimiter::increment('send-message:'.$user->id, amount: 5);
RateLimiter::increment('send-message:'.$user->id, amount: 5);
Determining Limiter Availability
When a key has no more attempts left, the availableIn method returns the
number of seconds remaining until more attempts will be available:
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...
use Illuminate\Support\Facades\RateLimiter;
if (RateLimiter::tooManyAttempts('send-message:'.$user->id, $perMinute = 5)) {
$seconds = RateLimiter::availableIn('send-message:'.$user->id);
return 'You may try again in '.$seconds.' seconds.';
}
RateLimiter::increment('send-message:'.$user->id);
// Send message...
Clearing Attempts
You may reset the number of attempts for a given rate limiter key using the
clear method. For example, you may reset the number of attempts when a given
message is read by the receiver:
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}
use App\Models\Message;
use Illuminate\Support\Facades\RateLimiter;
/**
* Mark the message as read.
*/
public function read(Message $message): Message
{
$message->markAsRead();
RateLimiter::clear('send-message:'.$message->user_id);
return $message;
}