# Laravel Middleware https://laravel.com/docs/8.x/middleware 檢查和過濾 HTTP 請求,像是判斷是不是已認證使用者,如果不是認證的可能會被導到某個地方,額外應用的方式可能有 logging middleware 去 log 所有進來的 request # 檔案存放的位置 都存放在 app/Http/Middleware 這個木路底下 # 建立 ```php= php artisan make:middleware EnsureTokenIsValid ``` 可以把 middleware 想成是 HTTP request 需要通過的一系列關卡,每個關卡都有自己要處理的事情符合就通過,不符合可能就拒絕請求這樣 # 種類 ## before middleware 被 application 處理前就執行 ```php= class BeforeMiddleware { public function handle($request, Closure $next) { // Perform action return $next($request); } } ``` ## after middleware 被 application 處理後才執行 ```php= class AfterMiddleware { public function handle($request, Closure $next) { $response = $next($request); // Perform action return $response; } } ``` # 註冊 需要在 app/Http/Kernel.php 裡面進行註冊或設定 ## Global 如果有有 middleware 需要每次請求都被執行可以放在 $middleware 這個陣列裡 ## 給 route 用 需要在 $routeMiddleware 這個屬性裡面設定 key name 和對應的檔案,下面範例 ```php= // App\Http\Kernel protected $routeMiddleware = [ 'auth' => \App\Http\Middleware\Authenticate::class ]; // route 使用單一 middleware Route::get('/profile', function () { // })->middleware('auth'); // route 使用多個 middleware Route::get('/', function () { // })->middleware(['first', 'second']); // 也可以用 class 的寫法 use App\Http\Middleware\EnsureTokenIsValid; Route::get('/profile', function () { // })->middleware(EnsureTokenIsValid::class); ``` ## 不包含某個 middleware ```php= Route::get('/profile', function () { // })->withoutMiddleware([EnsureTokenIsValid::class]); ``` # Middleware Groups 可以看一下 App\Http\Kernel 裡 $middlewareGroups 這個屬性預設是有 web 和 api 這兩個 key 在看一下 RouteServiceProvider 裡有用到這兩個 key 代表這兩個 route file 都會套用 對應的 middleware group ```php= // App\Http\Kernel protected $middlewareGroups = [ 'web' => [ ... ], 'api' => [ ... ], ]; // RouteServiceProvider public function boot() { $this->configureRateLimiting(); $this->routes(function () { Route::prefix('api') ->middleware('api') ->namespace($this->namespace) ->group(base_path('routes/api.php')); Route::middleware('web') ->namespace($this->namespace) ->group(base_path('routes/web.php')); }); } ``` 如果想要在 route file 裡使用也可以,就是將 key name 帶入就好,但其實各自 route file 就會帶入各自的 middleware group 了 ```php= Route::get('/', function () { // })->middleware('web'); Route::middleware(['web'])->group(function () { // }); ``` # 順序執行 middleware 如果需要有順序去執行的話可以在 `app/Http/Kernel.php` 新增一個 $middlewarePriority 屬性的陣列然後按照你想要的順序去排序 middleware,預設上沒有這個屬性 # middleware 參數 ``` // middleware - $role 是額外帶進來的 public function handle($request, Closure $next, $role){ // action } // route file Route::put('/post/{id}', function ($id) { // })->middleware('role:editor'); ``` # Terminable Middleware 當回傳回瀏覽器時可能會需要做一些其它處理,可以在 middleware 檔案裡新增 terminate method 去做你想做的 ```php= class TerminatingMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { return $next($request); } /** * Handle tasks after the response has been sent to the browser. * * @param \Illuminate\Http\Request $request * @param \Illuminate\Http\Response $response * @return void */ public function terminate($request, $response) { // ... } } ``` ## 註冊 Terminable Middleware 在 app/Http/Kernel.php 裡註冊,註冊在 route 或 global middleware 屬性 裡 ###### tags: `2021` `laravel` `middleware` `中介層` {%hackmd BJrTq20hE %}