簡介#
Laravel 中間件提供了一種方便的機制來過濾進入應用的HTTP請求。例如,Laravel 內置了一個中間件來驗證用戶的身份認證 ,
如果沒有通過身份認證,中間件會將用戶重定向到登陸界面,但是,如果用戶被認證,中間件將允許該請求進一步進入該應用。
當然,除了身份認證以外,還可以編寫另外的中間件來執行各種任務,例如:CORS中間件可以負責為所有離開應用的響應添加合適的頭部信息:
日志中間件可以記錄所有傳入應用的請求。
Laravel 自帶了一些中間件,包括身份驗證,CSRF 保護等,所有這些中間件都位於
app/Http/Middleware 目錄。
定義中間件#
運行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 Closre;
class AfterMiddleware
{
public function handle($request,Closure $next)
{
$response = $next($request);
// 執行動作
return $request;
}
}
注冊中間件
全局中間件#
如果你想讓中間件在你應用的每個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);
中間件組#
有時你可能想用單一的 鍵 為幾個中間件分組。使其更容易分配到路由。可以使用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(){
//
})->midlleware('web');
Route::group(['middleware'=>['web']],function(){
//
})
中間件參數#
中間件也可以接受額外的參數,例如,如果應用需要在運行特定操作前驗證經過身份認證的用戶是否具備給定的 角色 你可以新建一個 CleckRole
中間件,由它來接收 角色 名稱作為附加參數。
附加的中間件參數應該在 $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 文件的全局中間件中。
在你的中間件上調用terninate調用時,Laravel會從服務容器中解析
一個新的中間件實例,如果要在調用 handle和terminate 方法時
使用同一個中間件實例,就使用容器的singleton方法向容器注冊中間件。