Out of the box, Laravel provides two middleware that can be used for rate limiting (throttling):
\Illuminate\Routing\Middleware\ThrottleRequests::class
\Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class
As the documentation states, if you are using Redis as the cache driver, you can change the mapping in the Kernel.php
like so:
/**
* The application's middleware aliases.
*
* Aliases may be used instead of class names to conveniently assign middleware to routes and groups.
*
* @var array<string, class-string|string>
*/
protected $middlewareAliases = [
// ...
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class
// ...
];
The issue with this is that the above is not dynamic, dependent on the environment. For instance, on my staging
and production
environments, I utilise Redis, but on my local
and development
environments, I do not.
There is an obvious dirty fix, something like this (Kernel.php
):
/**
* The application's middleware aliases.
*
* Aliases may be used instead of class names to conveniently assign middleware to routes and groups.
*
* @var array<string, class-string|string>
*/
protected $middlewareAliases = [
// ...
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class
// ...
];
/**
* Create a new HTTP kernel instance.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @param \Illuminate\Routing\Router $router
* @return void
*/
public function __construct(Application $app, Router $router)
{
if ($app->environment('production')) {
$this->middlewareAliases['throttle'] = \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class;
}
parent::__construct($app, $router);
}
Is there a 'standard' way to achieve this without having to override the Kernel
constructor? Essentially, I would like my app to dynamically choose the relevant middleware dependant on whether the environment is set to production
(or, the default cache store is set to redis
).
The above solution does not work as the Kernel is accessed prior to the app being bootstrapped, thus the environment is not available at this point. The other solution I am now looking into is extending the base ThrottleRequests
class in order dynamically call the relevant class.
After much research and testing, I concluded that the best solution was to dynamically set the throttle
middleware in the RouteServiceProvider
like so:
class RouteServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot(): void
{
$this->registerThrottleMiddleware();
}
/**
* Register the middleware used for throttling requests.
*
* @return void
*/
private function registerThrottleMiddleware(): void
{
$router = app()->make('router');
$middleware = config('cache.default') !== 'redis'
? \Illuminate\Routing\Middleware\ThrottleRequests::class
: \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class;
$router->aliasMiddleware('throttle', $middleware);
}
}