# 中間件
- [簡介](#introduction)
- [定義中間件](#defining-middleware)
- [注冊中間件](#registering-middleware)
- [全局中間件](#global-middleware)
- [為路由分配中間件](#assigning-middleware-to-routes)
- [中間件組](#middleware-groups)
- [中間件參數](#middleware-parameters)
- [Terminable 中間件](#terminable-middleware)
<a name="introduction"></a>
## 簡介
Laravel 中間件提供了一種方便的機制來過濾進入應用的 HTTP 請求。例如,Laravel 內置了一個中間件來驗證用戶的身份認證。如果用戶沒有通過身份認證,中間件會將用戶重定向到登錄界面。但是,如果用戶被認證,中間件將允許該請求進一步進入該應用。
當然,除了身份認證以外,還可以編寫另外的中間件來執行各種任務。例如:CORS 中間件可以負責為所有離開應用的響應添加合適的頭部信息;日志中間件可以記錄所有傳入應用的請求。
Laravel 自帶了一些中間件,包括身份驗證、CSRF 保護等。所有這些中間件都位于 `app/Http/Middleware` 目錄。
<a name="defining-middleware"></a>
## 定義中間件
運行Artisan 命令 `make:middleware` 創建新的中間件:
php artisan make:middleware CheckAge
該命令將會在 `app/Http/Middleware` 目錄內新建一個 `CheckAge` 類。在這個中間件里,我們僅允許提供的參數 `age` 大于 200 的請求訪問該路由。否則,我們會將用戶重定向到 `home` 。
<?php
namespace App\Http\Middleware;
use Closure;
class CheckAge
{
/**
* 處理傳入的請求
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->age <= 200) {
return redirect('home');
}
return $next($request);
}
}
如你所見,若給定的 `age` 小于等于 `200`,那中間件將返回一個 HTTP 重定向到客戶端;否則,請求將進一步傳遞到應用中。要讓請求繼續傳遞到應用程序中(即允許「通過」中間件驗證的),只需使用 `$request` 作為參數去調用回調函數 `$next` 。
最好將中間件想象為一系列 HTTP 請求必須經過才能觸發你應用的「層」。每一層都會檢查請求(是否符合某些條件),(如果不符合)甚至可以(在請求訪問你的應用之前)完全拒絕掉。
### 前置 & 后置中間件
中間件是在請求之前或之后運行取決于中間件本身。例如,以下的中間件會在應用處理請求 **之前** 執行一些任務:
<?php
namespace App\Http\Middleware;
use Closure;
class BeforeMiddleware
{
public function handle($request, Closure $next)
{
// 執行動作
return $next($request);
}
}
而下面(這種寫法的)中間件會在應用處理請求 **之后** 執行其任務:
<?php
namespace App\Http\Middleware;
use Closure;
class AfterMiddleware
{
public function handle($request, Closure $next)
{
$response = $next($request);
// 執行動作
return $response;
}
}
<a name="registering-middleware"></a>
## 注冊中間件
<a name="global-middleware"></a>
### 全局中間件
如果你想讓中間件在你應用的每個 HTTP 請求期間運行,只需在 `app/Http/Kernel.php` 類中的 `$middleware` 屬性里列出這個中間件類 。
<a name="assigning-middleware-to-routes"></a>
### 為路由分配中間件
如果要為特定的路由分配中間件,
如果想為特殊的路由指定中間件,首先應該在 `app/Http/Kernel.php` 文件內為該中間件指定一個 `鍵`。默認情況下,`Kernel` 類的 `$routeMiddleware` 屬性包含 Laravel 內置的中間件條目。要加入自定義的,只需把它附加到列表后并為其分配一個自定義 `鍵` 即可。例如:
// 在 App\Http\Kernel 類中
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
一旦在 Kernel 中定義了中間件,就可使用 `middleware` 方法將中間件分配給路由:
Route::get('admin/profile', function () {
//
})->middleware('auth');
你還可以為路由分配多個中間件:
Route::get('/', function () {
//
})->middleware('first', 'second');
分配中間件時,你還可以傳遞完整的類名:
use App\Http\Middleware\CheckAge;
Route::get('admin/profile', function () {
//
})->middleware(CheckAge::class);
<a name="middleware-groups"></a>
### 中間件組
有時你可能想用單一的 `鍵` 為幾個中間件分組,使其更容易分配到路由。可以使用 Kernel 類的 `$middlewareGroups` 屬性來實現。
Laravel 自帶的 `web` 和 `api` 中間件組包含了你可能會應用到 Web UI 和 API 路由的常見的中間件:
/**
* 應用程序的路由中間件組
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
'throttle:60,1',
'auth:api',
],
];
可以使用與單個中間件相同的語法將中間件組分配給路由和控制器操作。重申一遍,中間件組只是更方便地實現了一次為路由分配多個中間件。
Route::get('/', function () {
//
})->middleware('web');
Route::group(['middleware' => ['web']], function () {
//
});
> {tip} 無需任何操作,`RouteServiceProvider` 會自動將 `web` 中間件組應用于你的的 `routes/web.php` 文件。
<a name="middleware-parameters"></a>
## 中間件參數
中間件也可以接受額外的參數。例如,如果應用需要在運行特定操作前驗證經過身份認證的用戶是否具備給定的「角色」,你可以新建一個 `CheckRole` 中間件,由它來接收「角色」名稱作為附加參數。
附加的中間件參數應該在 `$next` 參數之后被傳遞:
<?php
namespace App\Http\Middleware;
use Closure;
class CheckRole
{
/**
* 處理傳入的請求
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $role
* @return mixed
*/
public function handle($request, Closure $next, $role)
{
if (! $request->user()->hasRole($role)) {
// 重定向...
}
return $next($request);
}
}
定義路由時通過一個 `:` 來隔開中間件名稱和參數來指定中間件參數。多個參數就使用逗號分隔:
Route::put('post/{id}', function ($id) {
//
})->middleware('role:editor');
<a name="terminable-middleware"></a>
## Terminable 中間件
有時中間件可能需要在 HTTP 響應發送到瀏覽器之后處理一些工作。比如,Laravel 內置的「session」中間件會在響應發送到瀏覽器之后將會話數據寫入存儲器中。如果你在中間件中定義一個 `terminate` 方法,則會在響應發送到瀏覽器后自動調用:
<?php
namespace Illuminate\Session\Middleware;
use Closure;
class StartSession
{
public function handle($request, Closure $next)
{
return $next($request);
}
public function terminate($request, $response)
{
// Store the session data...
}
}
`terminate` 方法應該同時接收和響應。一旦定義了這個中間件,你應該將它添加到路由列表或 `app/Http/Kernel.php` 文件的全局中間件中。
在你的中間件上調用 `terminate` 調用時,Laravel 會從 [服務容器](/docs/{{version}}/container) 中解析出一個新的中間件實例。如果要在調用 `handle` 和 `terminate` 方法時使用同一個中間件實例,就使用容器的 `singleton` 方法向容器注冊中間件。
## 譯者署名
| 用戶名 | 頭像 | 職能 | 簽名 |
|---|---|---|---|
| [@半夏](https://laravel-china.org/users/6928) | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/6928_1479451835.jpeg?imageView2/1/w/100/h/100"> | 翻譯 | [@半夏](https://github.com/mintgreen1108) |
| [@JokerLinly](https://laravel-china.org/users/5350) | <img class="avatar-66 rm-style" src="https://dn-phphub.qbox.me/uploads/avatars/5350_1481857380.jpg"> | Review | Stay Hungry. Stay Foolish. |
---
> {note} 歡迎任何形式的轉載,但請務必注明出處,尊重他人勞動共創開源社區。
>
> 轉載請注明:本文檔由 Laravel China 社區 [laravel-china.org](https://laravel-china.org) 組織翻譯,詳見 [翻譯召集帖](https://laravel-china.org/topics/5756/laravel-55-document-translation-call-come-and-join-the-translation)。
>
> 文檔永久地址: https://d.laravel-china.org
- 說明
- 翻譯說明
- 發行說明
- 升級說明
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- HomeStead
- Valet
- 核心架構
- 請求周期
- 服務容器
- 服務提供者
- 門面(Facades)
- Contracts
- 基礎功能
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- 重定向
- Session
- 表單驗證
- 錯誤與日志
- 前端開發
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全
- 用戶認證
- API認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- API 資源
- 序列化
- 測試
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Horizon
- Passport OAuth 認證
- Scout 全文搜索
- Socialite 社交化登錄
- 交流說明