預(yù)設(shè)情況下,Laravel提供了兩個(gè)中間件用於速率限制(節(jié)流):
\Illuminate\Routing\Middleware\ThrottleRequests::class \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class
如文件所述,如果您使用Redis作為快取驅(qū)動(dòng)程序,您可以在Kernel.php
中更改映射,如下所示:
/** * 應(yīng)用程序的中間件別名。 * * 別名可用于將中間件方便地分配給路由和組,而不是使用類名。 * * @var array<string, class-string|string> */ protected $middlewareAliases = [ // ... 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class // ... ];
問題在於上述內(nèi)容不是動(dòng)態(tài)的,而是依賴環(huán)境。例如,在我的staging
和production
環(huán)境中,我使用Redis,但在我的local
和development
環(huán)境中,我不使用Redis。
有一個(gè)明顯的髒解決方案,類似於這樣(Kernel.php
):
/** * 應(yīng)用程序的中間件別名。 * * 別名可用于將中間件方便地分配給路由和組,而不是使用類名。 * * @var array<string, class-string|string> */ protected $middlewareAliases = [ // ... 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class // ... ]; /** * 創(chuàng)建一個(gè)新的HTTP內(nèi)核實(shí)例。 * * @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); }
是否有一種「標(biāo)準(zhǔn)」方法可以在不重寫Kernel
建構(gòu)子的情況下實(shí)現(xiàn)這一點(diǎn)?基本上,我希望我的應(yīng)用程式可以根據(jù)環(huán)境是否設(shè)定為production
(或預(yù)設(shè)快取儲存設(shè)定為redis
)動(dòng)態(tài)選擇相關(guān)的中間件。
上述解決方案不起作用,因?yàn)樵谝龑?dǎo)應(yīng)用程式之前訪問內(nèi)核,因此此時(shí)環(huán)境不可用。我現(xiàn)在正在研究的另一種解決方案是擴(kuò)展基本的ThrottleRequests
類,以便動(dòng)態(tài)調(diào)用相關(guān)的類別。
經(jīng)過大量的研究和測試,我得出的結(jié)論是在RouteServiceProvider
中動(dòng)態(tài)設(shè)定throttle
中間件是最好的解決方案,程式碼如下:
class RouteServiceProvider extends ServiceProvider { /** * 啟動(dòng)任何應(yīng)用程序服務(wù)。 * * @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); } }