中介軟體
- #中間件
- ##介紹中間件群組
- #中間件的排序
介紹
中間件提供了一個方便的機制過濾進入應用程式的 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{ /** * Handle an incoming request. * * @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); // Perform action return $response; } }
註冊中間件
##全域中間件如果你希望中間件在應用處理每個HTTP 請求期間運行。只需要在app/Http/Kernel.php 中的
$middleware 屬性中列出這個中間件
為路由分配中間件
假設你下想為指定的路由分配中間件,首先應該在app/Http/Kernel.php
檔案內為該中間件分配一個鍵。預設情況下,該類別中的 $routeMiddleware
屬性下包含了 Laravel 內建的中間件。若要加入自訂的中間件,只需將它附加到清單後並為其指派自訂鍵。例如:
// 在 App\Http\Kernel 类中... protected $routeMiddleware = [ 'auth' => \App\Http\Middleware\Authenticate::class, 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, 'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, 'can' => \Illuminate\Auth\Middleware\Authorize::class, 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, ];
一旦在HTTP 核心中定義好了中間件,就可以透過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);
中間元件
某些時候你可以希望使用一個鍵把多個中間件打包成一個群組,方便將他們應用到路由中去。你可以使用 Http 核心的 $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
。
Sorting(排序) 中間件
#很少情況下,你可能需要中間件以特定的順序執行,但是當它們被分配到路由時,你無法控制它們的順序。在這種情況下,可以使用 app/Http/Kernel.php
檔案的 $middlewarePriority
屬性指定中間件優先權:
/** * 中间件的优先级排序列表 * * 将会强制非全局中间件始终保持给定的顺序。 * * @var array */ protected $middlewarePriority = [ \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\Authenticate::class, \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Auth\Middleware\Authorize::class,];屬性指定中間件優先權:
<?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)) {
// Redirect...
}
return $next($request);
}
}
#中間件參數
CheckRole 中間件,由它來接收「角色」名稱作為附加參數。
$next 參數之後傳遞給中間件:
Route::put('post/{id}', function ($id) { // })->middleware('role:editor');定義路由時透過一個
<?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... } }###################
Terminable 中間件
有時,在準備好 HTTP 回應之後,中間件可能需要做一些工作。例如,Laravel 內建的「session」 中間件會在完全準備好回應後將會話資料寫入儲存體。如果你在中間件上定義了一個 terminate
方法,那麼它將會在回應準備傳送到瀏覽器之後自動呼叫。
terminate
方法應該同時接收請求和回應。定義了這個中間件之後,別忘了將它加入路由清單或 app/Http/Kernel.php
檔案的全域中間件。
當你在中間件上呼叫 terminate
方法的時候, Laravel 將從 服務容器 中解析出一個新的中間件實例。如果在呼叫 handle
和 terminate
方法的同時使用相同的中間件實例,請使用容器的 singleton
方法在容器中註冊中間件。