* * * * *
[TOC]
## 介紹
Laravel 中間件提供了一種方便的機制來過濾進入應用的 HTTP 請求。例如,Laravel 內置了一個中間件來驗證用戶的身份認證。如果用戶沒有通過身份認證,中間件會將用戶重定向到登錄界面。但是,如果用戶被認證,中間件將允許該請求進一步進入該應用。
當然,除了身份認證以外,還可以編寫另外的中間件來執行各種任務。例如:CORS 中間件可以負責為所有離開應用的響應添加合適的頭部信息;日志中間件可以記錄所有傳入應用的請求。
Laravel 自帶了一些中間件,包括身份驗證、CSRF 保護等。所有這些中間件都位于?`app/Http/Middleware`?目錄。
## 定義中間件
通過運行?`make:middleware`?Artisan 命令來創建新的中間件:
~~~
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)
{
// Perform action
return $next($request);
}
}
~~~
而接下來的這個中間件將在應用處理請求?**之后**?執行其任務:
~~~
<?php
namespace App\Http\Middleware;
use Closure;
class AfterMiddleware
{
public function handle($request, Closure $next)
{
$response = $next($request);
// 執行操作
return $response;
}
}
~~~
## 注冊中間件
### 全局中間件
假設你想讓中間件在應用處理每個HTTP請求期間運行,只需要在?`app/Http/Kernel.php`?中的?`$middleware`?屬性中列出這個中間件
### 為路由分配中間件
假設你想為指定的路由分配中間件,首先應該在?`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);
~~~
### 中間件組
某些時候你可能希望使用一個 key 把多個中間件打包成一個組,方便將他們應用到路由中。你可以使用 Http 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 () {
//
});
~~~
> {提示}?`RouteServiceProvider`?將?`web`?中間組自動應用到?`routes/web.php`?。
## 中間件參數
中間件也可以接受額外的參數。舉個例子,假如你的應用需要在執行特定操作之前驗證用戶是否為給定的 「角色」,你可以通過創建一個?`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');
~~~
## 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 會從?[服務容器](http://www.hmoore.net/tonyyu/laravel_5_6/786056)?中解析出一個新的中間件實例。如果要在調用?`handle`?和?`terminate`?方法時使用同一個中間件實例,就使用容器的 singleton 方法向容器注冊中間件。
- 前言
- 翻譯說明
- 發行說明
- 升級指南
- 貢獻導引
- 入門指南
- 安裝
- 配置信息
- 文件夾結構
- Homestead
- Valet
- 部署
- 核心架構
- 請求周期
- 服務容器
- 服務提供者
- Facades
- Contracts
- 基礎功能
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- URL
- Session
- 表單驗證
- 錯誤
- 日志
- 前端開發
- Blade 模板
- 本地化
- 前端指南
- 編輯資源 Mix
- 安全相關
- 用戶認證
- Passport OAuth 認證
- 用戶授權
- 加密解密
- 哈希
- 重置密碼
- 綜合話題
- Artisan 命令行
- 廣播系統
- 緩存系統
- 集合
- 事件系統
- 文件存儲
- 輔助函數
- 郵件發送
- 消息通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫
- 快速入門
- 查詢構造器
- 分頁
- 數據庫遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 模型關聯
- Eloquent 集合
- 修改器
- API 資源
- 序列化
- 測試相關
- 快速入門
- HTTP 測試
- 瀏覽器測試 Dusk
- 數據庫測試
- 測試模擬器
- 官方擴展包
- Cashier 交易工具包
- Envoy 部署工具
- Horizon
- Scout 全文搜索
- Socialite 社會化登錄