More and more of my work in Laravel lately has been creating APIs. I have a manual rate limiter class I've been using, but I've had a sense that there's a cleaner way to do it. Unsurprisingly, when Taylor set out to write a rate limiter middleware for Laravel, he did it cleaner and better than I had.
Brief introduction to rate limiting #
If you're not familiar with it, rate limiting is a tool—most often used in APIs—that limits the rate at which any individual requester can make requests.
That means, for example, if some bot is hitting a particularly expensive API route a thousand times a minute, your application won't crash, because after the nth try, they will instead get a
429: Too Many Attempts.
response back from the server.
Usually a well-written application that implements rate limiting will also pass back three headers that might not be on another application:
X-RateLimit-Limit
, X-RateLimit-Remaining
, and Retry-After
(you'll only get Retry-After
if you've hit the limit). X-RateLimit-Limit
tells you the max number of requests you're allowed to make within this application's time period, X-RateLimit-Remaining
tells you how many requests you have left within this current time period, and Retry-After
tells you how many seconds to wait until you try again. (Retry-After
could also be a date instead of a number of seconds).Note: Each API chooses the time span it's rate limiting for. GitHub is per hour, Twitter is per 15-minute segment. This Laravel middleware is per minute.
How to use Laravel's rate-limiting middleware #
So, on to the new feature in Laravel 5.2. There's a new
throttle
middleware that you can use. Let's take a look at our API group:Route::group(['prefix' => 'api'], function () {
Route::get('people', function () {
return Person::all();
});
});
Let's apply a throttle to it. The default throttle limits it to 60 attempts per minute, and disables their access for a single minute if they hit the limit.
Route::group(['prefix' => 'api', 'middleware' => 'throttle'], function () {
Route::get('people', function () {
return Person::all();
});
});
If you make a request to this
api/people
route, you'll now see the following lines in the response headers:HTTP/1.1 200 OK
... other headers here ...
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
Remember, this response means:
A) This request succeeded (the status is
B) You can try this route 60 times per minute
C) You have 59 requests left for this minute
200
)B) You can try this route 60 times per minute
C) You have 59 requests left for this minute
What response would we get if we went over the rate limit?
HTTP/1.1 429 Too Many Requests
... other headers here ...
Retry-After: 60
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
And the actual content of the response would be a string: "Too Many Attempts."
What if we tried again after 30 seconds?
HTTP/1.1 429 Too Many Requests
... other headers here ...
Retry-After: 30
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
Same response, except the
Retry-After
timer that's telling us how long to wait has ticked down by 30 seconds.
Customizing the throttle
middleware #
Let's do a bit of customization. We want to limit it to 5 attempts per minute.
Route::group(['prefix' => 'api', 'middleware' => 'throttle:5'], function () {
Route::get('people', function () {
return Person::all();
});
});
And if we want to change it so that, if someone hits the limit, they can't try again for another 10 minutes?
Route::group(['prefix' => 'api', 'middleware' => 'throttle:5,10'], function () {
Route::get('people', function () {
return Person::all();
});
});
That's all there is to it!
You can see the code that's supporting this here: ThrottlesRequests.php
from : https://mattstauffer.co/blog/api-rate-limiting-in-laravel-5-2
沒有留言:
張貼留言