> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# 中介軟體

> 說明如何運用 Laravel 中介軟體對 HTTP 請求進行過濾與前處理。

## 中介軟體是什麼

中介軟體是檢查、過濾進入應用程式的 HTTP 請求的機制。
可在請求傳到控制器前後插入處理。

例如 Laravel 內建的認證中介軟體：
若使用者未認證則導向登入畫面；若已認證則將請求傳到應用程式內部。

除了認證，也可為日誌記錄、CSRF 保護、速率限制等各種用途建立中介軟體。Laravel 13 的 CSRF 保護詳細請參閱 [CSRF 保護](/zh-TW/csrf)。

<Info>
  使用者定義的中介軟體通常放在 `app/Http/Middleware` 目錄。
</Info>

```mermaid theme={null}
flowchart TD
    A["HTTP 請求"] --> B["全域中介軟體<br>（套用至所有請求）"]
    B --> C["路由中介軟體<br>（套用至特定路由）"]
    C --> D["控制器 / 閉包"]
    D --> E["產生回應"]
    E --> F["路由中介軟體<br>（後處理）"]
    F --> G["全域中介軟體<br>（後處理）"]
    G --> H["HTTP 回應"]
```

## 內建中介軟體

Laravel 預設提供 `web` 與 `api` 兩個中介軟體群組。
`routes/web.php` 會自動套用 `web` 群組，`routes/api.php` 會自動套用 `api` 群組。

| `web` 中介軟體群組                     |
| -------------------------------- |
| `EncryptCookies`                 |
| `AddQueuedCookiesToResponse`     |
| `StartSession`                   |
| `ShareErrorsFromSession`         |
| `PreventRequestForgery`（CSRF 保護） |
| `SubstituteBindings`             |

此外，常用中介軟體有預設別名，可以用簡短名稱參照。

| 別名         | 中介軟體                                                 |
| ---------- | ---------------------------------------------------- |
| `auth`     | `Illuminate\Auth\Middleware\Authenticate`            |
| `guest`    | `Illuminate\Auth\Middleware\RedirectIfAuthenticated` |
| `verified` | `Illuminate\Auth\Middleware\EnsureEmailIsVerified`   |
| `throttle` | `Illuminate\Routing\Middleware\ThrottleRequests`     |

## 建立中介軟體

以 `make:middleware` Artisan 指令建立新的中介軟體。

```shell theme={null}
php artisan make:middleware EnsureTokenIsValid
```

會產生 `app/Http/Middleware/EnsureTokenIsValid.php`。
在 `handle` 方法中撰寫處理請求的邏輯。

```php theme={null}
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureTokenIsValid
{
    /**
     * 處理收到的請求
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        if ($request->input('token') !== 'my-secret-token') {
            return redirect('/home');
        }

        return $next($request);
    }
}
```

呼叫 `$next($request)` 會把請求傳給後續處理。
若不符條件則以 redirect 或回應中止請求。

### 請求前後的處理

中介軟體可在請求的**前**或**後**執行處理。

```php theme={null}
// 於請求前處理
public function handle(Request $request, Closure $next): Response
{
    // 在這裡寫前置處理

    return $next($request);
}
```

```php theme={null}
// 於回應後處理
public function handle(Request $request, Closure $next): Response
{
    $response = $next($request);

    // 在這裡寫後置處理

    return $response;
}
```

## 註冊中介軟體

### 全域中介軟體

若要對所有請求執行中介軟體，可在 `bootstrap/app.php` 的 `withMiddleware` 中將它加入全域堆疊。

```php theme={null}
// bootstrap/app.php
use App\Http\Middleware\EnsureTokenIsValid;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->append(EnsureTokenIsValid::class);
    });
```

`append` 會加到堆疊末端。若要加到最前面請用 `prepend`。

### 套用中介軟體到路由

若要只對特定路由套用中介軟體，可在路由定義呼叫 `middleware` 方法。

```php theme={null}
use App\Http\Middleware\EnsureTokenIsValid;

Route::get('/profile', function () {
    // ...
})->middleware(EnsureTokenIsValid::class);
```

要套用多個中介軟體時傳入陣列：

```php theme={null}
Route::get('/', function () {
    // ...
})->middleware([First::class, Second::class]);
```

若要排除某條路由的中介軟體，可用 `withoutMiddleware`。

```php theme={null}
use App\Http\Middleware\EnsureTokenIsValid;

Route::middleware([EnsureTokenIsValid::class])->group(function () {
    Route::get('/', function () {
        // 此路由會套用中介軟體
    });

    Route::get('/profile', function () {
        // 此路由排除中介軟體
    })->withoutMiddleware([EnsureTokenIsValid::class]);
});
```

### 中介軟體別名

可為冗長的類別名稱定義短別名，於 `bootstrap/app.php` 設定：

```php theme={null}
// bootstrap/app.php
use App\Http\Middleware\EnsureUserIsSubscribed;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->alias([
            'subscribed' => EnsureUserIsSubscribed::class,
        ]);
    });
```

以別名套用到路由：

```php theme={null}
Route::get('/profile', function () {
    // ...
})->middleware('subscribed');
```

## 中介軟體群組

將多個中介軟體以一個 key 集合，可讓路由套用更方便。
在 `bootstrap/app.php` 用 `appendToGroup` 或 `prependToGroup`：

```php theme={null}
// bootstrap/app.php
use App\Http\Middleware\First;
use App\Http\Middleware\Second;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->appendToGroup('group-name', [
            First::class,
            Second::class,
        ]);
    });
```

群組可以像一般中介軟體那樣套用到路由：

```php theme={null}
Route::get('/', function () {
    // ...
})->middleware('group-name');

Route::middleware(['group-name'])->group(function () {
    // ...
});
```

若要加入既有的 `web` 或 `api` 群組，可使用專用方法：

```php theme={null}
// bootstrap/app.php
use App\Http\Middleware\EnsureUserIsSubscribed;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->web(append: [
            EnsureUserIsSubscribed::class,
        ]);
    });
```

## 中介軟體參數

中介軟體可接收額外參數。
於 `handle` 方法的 `$next` 之後加上參數即可。

```php theme={null}
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureUserHasRole
{
    public function handle(Request $request, Closure $next, string $role): Response
    {
        if (! $request->user()->hasRole($role)) {
            return redirect('/home');
        }

        return $next($request);
    }
}
```

在路由定義中，以 `:` 分隔中介軟體名稱與參數：

```php theme={null}
use App\Http\Middleware\EnsureUserHasRole;

Route::put('/post/{id}', function (string $id) {
    // ...
})->middleware(EnsureUserHasRole::class.':editor');
```

多個參數以逗號分隔：

```php theme={null}
Route::put('/post/{id}', function (string $id) {
    // ...
})->middleware(EnsureUserHasRole::class.':editor,publisher');
```

## 實例：認證檢查中介軟體

簡單的把未登入使用者導向登入頁的範例：

```shell theme={null}
php artisan make:middleware RedirectIfNotAuthenticated
```

```php theme={null}
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class RedirectIfNotAuthenticated
{
    public function handle(Request $request, Closure $next): Response
    {
        if (! $request->user()) {
            return redirect('/login');
        }

        return $next($request);
    }
}
```

套用到路由：

```php theme={null}
Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(RedirectIfNotAuthenticated::class);
```

<Tip>
  Laravel 內建了認證用的 `auth` 中介軟體。在自行實作前，先確認既有中介軟體是否已能滿足需求。
</Tip>

## 下一步

<Card title="HTTP 請求" icon="globe" href="/zh-TW/requests">
  學習如何在控制器中取得請求資料。
</Card>


## Related topics

- [Laravel Folio](/zh-TW/folio.md)
- [在地化](/zh-TW/localization.md)
- [日誌](/zh-TW/logging.md)
- [用 Laravel 構建 MCP 伺服器](/zh-TW/advanced/mcp-server.md)
- [Context（脈絡）](/zh-TW/context.md)
