简体   繁体   中英

Laravel throttle rate limiter limites access too early

I'm working with Laravel 5.8 and I wanted to apply a Rate Limiter that limits the sending request to 500 per minute .

So I tried adding this throttle to the route group:

Route::middleware('throttle:500,1')->group(function () {
    ...
});

So this means that limits access to the routes after 500 requests in 1 minute.

Now the problem is I get 429 | Too Many Requests too soon!

I mean, it does not seem to be sending 500 requests in a minute but it limits the access somehow.

So what's going wrong here? Why I get Too Many Requests message too early?

The throttle middleware requests are calculated together if you have another throttle group, these calculated together and may that group consume your limits

Route::get('example1', function () {
    return 'ans1';

})->middleware('throttle:5,1');

Route::get('example2', function () {
    return 'ans2';

})->middleware('throttle:5,1');

In above case, you have 2 route but if you send 2 request to example1 and 3 request to example2, your rate limit will finish for both of them and you got 429 | Too Many Requests error.

If you're using multiple throttle middlewares in your group and it's nested routes like this:

Route::middleware('throttle:500,1')->group(function () {
    Route::post('/foo', 'bar@foo')->middleware('throttle:5,60');
});

the throttle middleware counts each requests twice. for solving this issue, you must make sure that each route has only one throttle middleware.

But sometimes even though the middleware has been used only once, the request count is still wrong. in that cases, you can make your own customized throttle middleware that takes an extra argument for naming throttle key and prevent re-counting requests (based on this ).

To do this, you must first create a middleware (according to this ):

php artisan make:middleware CustomThrottleMiddleware

and then, replace the contents with:

<?php

namespace App\Http\Middleware;

use Closure;
use RuntimeException;
use Illuminate\Routing\Middleware\ThrottleRequests;

class CustomThrottleMiddleware extends ThrottleRequests
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @param  int|string  $maxAttempts
     * @param  float|int  $decayMinutes
     * @param  string $keyAppend
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @throws \Illuminate\Http\Exceptions\ThrottleRequestsException
     */
    public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1, $keyAppend = '')
    {
        $key = $this->resolveRequestSignature($request, $keyAppend);

        $maxAttempts = $this->resolveMaxAttempts($request, $maxAttempts);

        if ($this->limiter->tooManyAttempts($key, $maxAttempts)) {
            throw $this->buildException($key, $maxAttempts);
        }

        $this->limiter->hit($key, $decayMinutes * 60);

        $response = $next($request);

        return $this->addHeaders(
            $response, $maxAttempts,
            $this->calculateRemainingAttempts($key, $maxAttempts)
        );
    }

    /**
     * Resolve request signature.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  string $keyAppend
     * @return string
     *
     * @throws \RuntimeException
     */
    protected function resolveRequestSignature($request, $keyAppend='')
    {
        if ($user = $request->user()) {
            return sha1($user->getAuthIdentifier().$keyAppend);
        }

        if ($route = $request->route()) {
            return sha1($route->getDomain().'|'.$request->ip().$keyAppend);
        }

        throw new RuntimeException('Unable to generate the request signature. Route unavailable.');
    }
}

after doing that, you must to register the middleware by updating the app/Http/Kernel.php file:

protected $routeMiddleware = [
    //...
    'custom_throttle' => \App\Http\Middleware\CustomThrottleMiddleware::class,
];

now you can use this new customized throttle middleware in your routes, something like this:

Route::middleware('throttle:500,1')->group(function () {
    Route::post('/foo', 'bar@foo')->middleware('custom_throttle:5,60,foo');
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM