By default, Laravel provides two middlewares 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 Kernel.php
like this:
/** * 应用程序的中间件别名。 * * 别名可用于将中间件方便地分配给路由和组,而不是使用类名。 * * @var array<string, class-string|string> */ protected $middlewareAliases = [ // ... 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class // ... ];
The problem is that the above is not dynamic but environment dependent. For example, in my staging
and production
environments I use Redis, but in my local
and development
environments I Not using Redis.
There is an obvious dirty solution, something like this (Kernel.php
):
/** * 应用程序的中间件别名。 * * 别名可用于将中间件方便地分配给路由和组,而不是使用类名。 * * @var array<string, class-string|string> */ protected $middlewareAliases = [ // ... 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class // ... ]; /** * 创建一个新的HTTP内核实例。 * * @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 overriding the Kernel
constructor? Basically, I want my application to dynamically select the relevant middleware based on whether the environment is set to production
(or the default cache storage is set to redis
).
The above solution does not work because the kernel is accessed before the application is booted, so the environment is not available at this time. Another solution I'm looking into now is to extend the base ThrottleRequests
class so that the relevant classes are called dynamically.
P粉0434322102024-01-11 16:27:49
After a lot of research and testing, I came to the conclusion that dynamically setting the throttle
middleware in RouteServiceProvider
is the best solution, the code is as follows:
class RouteServiceProvider extends ServiceProvider { /** * 启动任何应用程序服务。 * * @return void */ public function boot(): void { $this->registerThrottleMiddleware(); } /** * 注册用于限制请求的中间件。 * * @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); } }