2025年6月11日 星期三

如何解釋 Laravel 的 Middleware 功能與使用場景?

 好的,我們來詳細解釋 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 的功能

  1. 請求前處理 (Before Middleware): 在請求到達控制器之前執行,這是最常見的用法。例如,檢查使用者是否已登入,如果沒有,就重新導向到登入頁面。
  2. 請求後處理 (After Middleware): 在控制器執行完畢並生成響應之後執行。例如,修改響應內容、添加額外標頭、記錄響應時間等。
  3. 條件式執行: 你可以根據請求的特定條件來決定是否讓 Middleware 執行。
  4. 鏈式處理: 多個 Middleware 可以組成一個鏈,請求會依序經過每個 Middleware。

如何創建和使用 Middleware?

1. 創建 Middleware

使用 Artisan 命令來創建一個新的 Middleware:

Bash
php artisan make:middleware CheckAge

這會在 app/Http/Middleware 目錄下生成一個新的檔案 CheckAge.php

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。
    PHP
    protected $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 組合成一個群組,然後一次性應用到多個路由上。最常見的是 webapi 群組。
    • web 群組: 包含處理 Session、CSRF 保護、Cookie 加密等網頁應用程式常用的 Middleware。通常你的大部分網頁路由都會使用這個群組。
    • api 群組: 專為 API 路由設計,通常沒有 Session 和 CSRF 保護。
    PHP
    protected $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 設定一個簡短的鍵名,然後可以在路由定義中使用這些鍵名。
    PHP
    protected $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. 應用到特定路由:
PHP
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. 應用到路由群組:
PHP
// 使用路由群組應用 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 應用程式中非常實用,以下是一些常見的使用場景:

  1. 身份驗證 (Authentication):

    • 場景: 檢查使用者是否已登入。如果未登入,則重新導向到登入頁面。
    • Laravel 預設: auth Middleware。
    • 範例: 保護只有登入使用者才能存取的頁面。
  2. 授權檢查 (Authorization / Role-based Access Control):

    • 場景: 檢查登入使用者是否具有執行特定操作或存取特定資源的權限(例如:只有管理員才能進入後台)。
    • 範例: 創建一個 CheckRole Middleware,根據使用者角色判斷是否允許訪問。
  3. CSRF 保護 (Cross-Site Request Forgery Protection):

    • 場景: 防止惡意網站冒充使用者發送請求。
    • Laravel 預設: VerifyCsrfToken Middleware (web Middleware 群組的一部分)。
  4. Cookie 加密/解密:

    • 場景: 在請求進入應用程式前解密 Cookies,在響應發送出去前加密 Cookies。
    • Laravel 預設: EncryptCookies Middleware (web Middleware 群組的一部分)。
  5. 日誌記錄 (Logging):

    • 場景: 記錄每個請求的詳細資訊,例如請求 URL、IP 地址、請求方法、響應時間等。
    • 範例: 創建一個 LogRequests Middleware,在請求前記錄進入時間,在請求後記錄響應時間和結果。
  6. 流量節流 (Rate Limiting):

    • 場景: 限制使用者在一定時間內發送請求的次數,防止惡意攻擊或資源濫用(例如:API 請求次數限制)。
    • Laravel 預設: throttle Middleware。
    • 範例: ->middleware('throttle:60,1') 限制每分鐘 60 個請求。
  7. CORS 處理 (Cross-Origin Resource Sharing):

    • 場景: 處理來自不同來源的網頁請求,設定必要的 HTTP 響應標頭。
    • Laravel 預設: HandleCors Middleware (通常由 laravel/cors 套件提供)。
  8. 維護模式 (Maintenance Mode):

    • 場景: 當網站處於維護狀態時,阻止所有請求,並顯示一個維護頁面。
    • Laravel 預設: PreventRequestsDuringMaintenance Middleware。
  9. 請求/響應數據修改:

    • 場景: 在控制器處理之前,對請求輸入進行清理、驗證或格式化。在控制器處理之後,對響應數據進行壓縮、添加標頭或轉換格式。
    • 範例: 將所有傳入的字串 trim 掉空白字元,或者將所有響應轉換為小寫。
  10. 多語系處理:

    • 場景: 根據請求的語言設定來載入不同的語言檔案。
    • 範例: 檢查請求頭中的 Accept-Language 或 URL 參數,然後設定應用程式的語系。

總結

Laravel 的 Middleware 提供了一個非常優雅和彈性的方式來處理 HTTP 請求的「前處理」和「後處理」邏輯。它將這些橫切關注點 (cross-cutting concerns) 從控制器中分離出來,使得控制器更專注於業務邏輯,提高了代碼的可讀性、可維護性和可重用性。掌握 Middleware 是 Laravel 開發中非常重要的一環。

沒有留言:

張貼留言

網誌存檔