好的,我們來詳細解釋 Laravel 的 Middleware 功能與使用場景。
什麼是 Laravel 的 Middleware (中介層)?
在 Laravel 框架中,Middleware (中介層) 是一種強大的機制,它允許你在 HTTP 請求到達應用程式的核心邏輯(例如控制器)之前或之後執行特定的任務。你可以把它想像成一個網站請求的「守衛」或「篩檢器」。
當一個 HTTP 請求進入你的 Laravel 應用程式時,它不會直接進入路由或控制器。相反,它會依序經過你定義的一系列 Middleware。每個 Middleware 都有機會檢查請求、執行一些操作(例如驗證使用者身份、記錄日誌、修改請求資料),然後決定是否將請求傳遞給下一個 Middleware 或最終的控制器。
Middleware 位於 HTTP 請求生命週期的中間,這就是它被稱為「中介層」的原因。
Laravel Middleware 的執行流程簡圖:
客戶端請求
↓
(核心) Bootstrap
↓
Middleware 1 (例如:加密 Cookies)
↓
Middleware 2 (例如:驗證 CSRF Token)
↓
Middleware 3 (例如:處理身份驗證)
↓
... 其他 Middleware ...
↓
路由器 (Router) 匹配路由
↓
控制器方法 / 閉包路由
↓
(執行應用程式邏輯)
↓
控制器返回響應
↓
... Middleware 3 (後處理) ...
↓
... Middleware 2 (後處理) ...
↓
... Middleware 1 (後處理) ...
↓
將響應傳回客戶端
每個 Middleware 都會接收到 $request
物件,並且可以透過 $next
閉包將請求傳遞給下一個 Middleware。
Middleware 的功能
- 請求前處理 (Before Middleware): 在請求到達控制器之前執行,這是最常見的用法。例如,檢查使用者是否已登入,如果沒有,就重新導向到登入頁面。
- 請求後處理 (After Middleware): 在控制器執行完畢並生成響應之後執行。例如,修改響應內容、添加額外標頭、記錄響應時間等。
- 條件式執行: 你可以根據請求的特定條件來決定是否讓 Middleware 執行。
- 鏈式處理: 多個 Middleware 可以組成一個鏈,請求會依序經過每個 Middleware。
如何創建和使用 Middleware?
1. 創建 Middleware
使用 Artisan 命令來創建一個新的 Middleware:
php artisan make:middleware CheckAge
這會在 app/Http/Middleware
目錄下生成一個新的檔案 CheckAge.php
:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class CheckAge
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
// 這裡可以執行請求前處理邏輯
if ($request->age <= 20) {
return redirect('home'); // 如果年齡小於等於 20,重新導向到 'home' 頁面
}
// 將請求傳遞給下一個 Middleware 或控制器
$response = $next($request);
// 這裡可以執行請求後處理邏輯
// 例如:$response->header('X-Custom-Header', 'Value');
return $response;
}
}
在 handle
方法中:
$request
:代表傳入的 HTTP 請求。$next
:一個閉包,用於將請求傳遞給下一個 Middleware 或最終的控制器。你必須呼叫$next($request)
來繼續請求流程。- 如果你在
$next($request)
之前返回一個響應(例如return redirect(...)
或return response(...)
),則後續的 Middleware 和控制器將不會被執行。 $response = $next($request);
這一行獲取了控制器或下一個 Middleware 返回的響應,你可以在其後對響應進行修改。
2. 註冊 Middleware
創建 Middleware 後,你需要將它註冊到 Laravel 應用程式中,這樣 Laravel 才知道它的存在。註冊通常在 app/Http/Kernel.php
檔案中進行。
Kernel.php
中有三個主要的 Middleware 屬性:
$middleware
: 全局 Middleware。所有請求都會經過這些 Middleware。PHPprotected $middleware = [ \App\Http\Middleware\TrustProxies::class, \App\Http\Middleware\PreventRequestsDuringMaintenance::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, // ... 其他預設的全局 Middleware // \App\Http\Middleware\CheckAge::class, // 如果需要所有請求都檢查年齡,則放在這裡 ];
$middlewareGroups
: Middleware 群組。你可以將多個 Middleware 組合成一個群組,然後一次性應用到多個路由上。最常見的是web
和api
群組。web
群組: 包含處理 Session、CSRF 保護、Cookie 加密等網頁應用程式常用的 Middleware。通常你的大部分網頁路由都會使用這個群組。api
群組: 專為 API 路由設計,通常沒有 Session 和 CSRF 保護。
PHPprotected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, // \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 'api' => [ // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, \Illuminate\Routing\Middleware\ThrottleRequests::class.':api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], ];
$routeMiddleware
: 路由 Middleware。為每個 Middleware 設定一個簡短的鍵名,然後可以在路由定義中使用這些鍵名。PHPprotected $routeMiddleware = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, // 註冊你自己的 CheckAge Middleware 'check.age' => \App\Http\Middleware\CheckAge::class, ];
3. 將 Middleware 應用到路由
註冊完成後,你可以在路由定義中應用這些 Middleware。
a. 應用到特定路由:
use App\Http\Controllers\DashboardController;
Route::get('/dashboard', [DashboardController::class, 'index'])->middleware('auth');
// 應用多個 Middleware
Route::get('/admin/panel', [AdminController::class, 'index'])->middleware('auth', 'check.age');
// 應用自定義的 CheckAge Middleware
Route::get('/check-age', function () {
return "你已經通過年齡檢查!";
})->middleware('check.age');
b. 應用到路由群組:
// 使用路由群組應用 Middleware
Route::middleware(['web', 'check.age'])->group(function () {
Route::get('/profile', function () {
//
});
Route::get('/settings', function () {
//
});
});
// 使用已有的 Middleware 群組
Route::middleware('auth')->group(function () {
Route::get('/order', function () {
//
});
Route::get('/cart', function () {
//
});
});
Middleware 的使用場景 (Use Cases)
Middleware 在 Laravel 應用程式中非常實用,以下是一些常見的使用場景:
-
身份驗證 (Authentication):
- 場景: 檢查使用者是否已登入。如果未登入,則重新導向到登入頁面。
- Laravel 預設:
auth
Middleware。 - 範例: 保護只有登入使用者才能存取的頁面。
-
授權檢查 (Authorization / Role-based Access Control):
- 場景: 檢查登入使用者是否具有執行特定操作或存取特定資源的權限(例如:只有管理員才能進入後台)。
- 範例: 創建一個
CheckRole
Middleware,根據使用者角色判斷是否允許訪問。
-
CSRF 保護 (Cross-Site Request Forgery Protection):
- 場景: 防止惡意網站冒充使用者發送請求。
- Laravel 預設:
VerifyCsrfToken
Middleware (web
Middleware 群組的一部分)。
-
Cookie 加密/解密:
- 場景: 在請求進入應用程式前解密 Cookies,在響應發送出去前加密 Cookies。
- Laravel 預設:
EncryptCookies
Middleware (web
Middleware 群組的一部分)。
-
日誌記錄 (Logging):
- 場景: 記錄每個請求的詳細資訊,例如請求 URL、IP 地址、請求方法、響應時間等。
- 範例: 創建一個
LogRequests
Middleware,在請求前記錄進入時間,在請求後記錄響應時間和結果。
-
流量節流 (Rate Limiting):
- 場景: 限制使用者在一定時間內發送請求的次數,防止惡意攻擊或資源濫用(例如:API 請求次數限制)。
- Laravel 預設:
throttle
Middleware。 - 範例:
->middleware('throttle:60,1')
限制每分鐘 60 個請求。
-
CORS 處理 (Cross-Origin Resource Sharing):
- 場景: 處理來自不同來源的網頁請求,設定必要的 HTTP 響應標頭。
- Laravel 預設:
HandleCors
Middleware (通常由laravel/cors
套件提供)。
-
維護模式 (Maintenance Mode):
- 場景: 當網站處於維護狀態時,阻止所有請求,並顯示一個維護頁面。
- Laravel 預設:
PreventRequestsDuringMaintenance
Middleware。
-
請求/響應數據修改:
- 場景: 在控制器處理之前,對請求輸入進行清理、驗證或格式化。在控制器處理之後,對響應數據進行壓縮、添加標頭或轉換格式。
- 範例: 將所有傳入的字串 trim 掉空白字元,或者將所有響應轉換為小寫。
-
多語系處理:
- 場景: 根據請求的語言設定來載入不同的語言檔案。
- 範例: 檢查請求頭中的
Accept-Language
或 URL 參數,然後設定應用程式的語系。
總結
Laravel 的 Middleware 提供了一個非常優雅和彈性的方式來處理 HTTP 請求的「前處理」和「後處理」邏輯。它將這些橫切關注點 (cross-cutting concerns) 從控制器中分離出來,使得控制器更專注於業務邏輯,提高了代碼的可讀性、可維護性和可重用性。掌握 Middleware 是 Laravel 開發中非常重要的一環。
沒有留言:
張貼留言