仅在 Laravel 生产中使用 Redis 进行节流

Ben*_*rey 1 php throttling rate-limiting redis laravel

背景

Laravel 开箱即用地提供了两个可用于速率限制(节流)的中间件:

\Illuminate\Routing\Middleware\ThrottleRequests::class
\Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class
Run Code Online (Sandbox Code Playgroud)

正如文档所述,如果您使用 Redis 作为缓存驱动程序,您可以像这样更改映射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\ThrottleRequestsWithRedis::class
    // ...
];
Run Code Online (Sandbox Code Playgroud)

问题

问题是上述内容不是动态的,依赖于环境。例如,在我的staging环境production中,我使用 Redis,但在我的local环境中development,我不使用 Redis。

潜在的解决方案

有一个明显的脏修复,如下所示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);
}
Run Code Online (Sandbox Code Playgroud)

是否有一种“标准”方法可以实现此目的而无需重写Kernel构造函数?本质上,我希望我的应用程序根据环境是否设置为production(或者默认缓存存储设置为redis)来动态选择相关的中间件。

更新

上述解决方案不起作用,因为在引导应用程序之前访问内核,因此此时环境不可用。我现在正在研究的另一个解决方案是扩展基ThrottleRequests类,以便动态调用相关类。

Ben*_*rey 5

经过大量研究和测试,我得出的结论是,最好的解决方案是动态设置throttle中间件,如下所示RouteServiceProvider

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);
    }
}
Run Code Online (Sandbox Code Playgroud)