Home  >  Q&A  >  body text

Laravel practice of using Redis for current limiting only in production environment

background

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
    // ...
];

question

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.

Possible solutions

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).

renew

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粉541565322P粉541565322306 days ago402

reply all(1)I'll reply

  • P粉043432210

    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);
        }
    }

    reply
    0
  • Cancelreply