默认情况下,Laravel提供了两个中间件用于速率限制(节流):
\Illuminate\Routing\Middleware\ThrottleRequests::class \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class
正如文档所述,如果您使用Redis作为缓存驱动程序,您可以在Kernel.php
中更改映射,如下所示:
/** * 应用程序的中间件别名。 * * 别名可用于将中间件方便地分配给路由和组,而不是使用类名。 * * @var array<string, class-string|string> */ protected $middlewareAliases = [ // ... 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class // ... ];
问题在于上述内容不是动态的,而是依赖于环境。例如,在我的staging
和production
环境中,我使用Redis,但在我的local
和development
环境中,我不使用Redis。
有一个明显的脏解决方案,类似于这样(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); }
是否有一种“标准”方法可以在不重写Kernel
构造函数的情况下实现这一点?基本上,我希望我的应用程序可以根据环境是否设置为production
(或者默认缓存存储设置为redis
)动态选择相关的中间件。
上述解决方案不起作用,因为在引导应用程序之前访问内核,因此此时环境不可用。我现在正在研究的另一种解决方案是扩展基本的ThrottleRequests
类,以便动态调用相关的类。
P粉0434322102024-01-11 16:27:49
经过大量的研究和测试,我得出的结论是在RouteServiceProvider
中动态设置throttle
中间件是最好的解决方案,代码如下:
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); } }