HTTP 中介層

簡介

HTTP 中介層提供一個方便的機制來過濾進入應用程式的 HTTP 請求,例如,Laravel 本身使用中介層來檢驗使用者身份驗證,如果使用者未經過身份驗證,中介層會將用戶導向登入頁面,然而,如果用戶通過身份驗證,中介層將會允許這個請求進入應用的其他部分。

當然,除了身份驗證之外,中介層也可以被用來執行各式各樣的任務,CORS 中介層負責替所有即將離開程式的回應加入適當的標頭。而日誌中介層可以記錄所有傳入應用程式的請求。

Laravel 框架已經內建一些中介層,包括維護、身份驗證、CSRF 保護,等等。所有的中介層都放在 app/Http/Middleware 目錄內。

建立中介層

要建立一個新的中介層,可以使用 make:middleware 這個 Artisan 指令:

php artisan make:middleware OldMiddleware

此指令將會在 app/Http/Middleware 目錄內建立一個名稱為 OldMiddleware 的類別。在這個中介層內我們只允許請求內的 age 變數大於 200 的才能存取路由,否則,我們會將用戶重新導向「home」這個 URI。

<?php namespace App\Http\Middleware;

use Closure;

class OldMiddleware {

	/**
	 * 執行請求過濾器。
	 *
	 * @param  \Illuminate\Http\Request  $request
	 * @param  \Closure  $next
	 * @return mixed
	 */
	public function handle($request, Closure $next)
	{
		if ($request->input('age') < 200)
		{
			return redirect('home');
		}

		return $next($request);
	}

}

如你所見,若是 age 小於 200,中介層將會回傳 HTTP 重新導向給用戶端,否則,請求將會進一步傳遞到應用程式。只需調用帶有 $request$next 方法,即可將請求傳遞到更深層的應用程式(允許通過中介層)。

HTTP 請求在實際碰觸到應用程式之前,最好是可以層層通過許多中介層,每一層都可以對請求進行檢查,甚至是完全拒絕請求。

/ 中介層

一個中介層是在請求前還是請求後執行要看中介層自己。這個中介層會在應用程式處理請求執行一些任務:

<?php namespace App\Http\Middleware;

use Closure;

class BeforeMiddleware implements Middleware {

	public function handle($request, Closure $next)
	{
		// 執行動作

		return $next($request);
	}
}

這個中介層則會在應用程式處理請求執行它的任務:

<?php namespace App\Http\Middleware;

use Closure;

class AfterMiddleware implements Middleware {

	public function handle($request, Closure $next)
	{
		$response = $next($request);

		// 執行動作

		return $response;
	}
}

註冊中介層

全域中介層

若是希望每個 HTTP 請求都經過一個中介層,只要將中介層的類別加入到 app/Http/Kernel.php$middleware 屬性清單列表中。

為路由指派中介層

如果你要指派中介層給特定的路由,你得先將中介層在 app/Http/Kernel.php 設定一個好記的鍵值,預設情況下,這個檔案內的 $routeMiddleware 屬性已包含了 Laravel 目前設定的中介層,你只需要在清單列表中加上一組自訂的鍵值即可。

中介層一旦在 HTTP kernel 檔案內被定義,你即可在路由選項內使用 middleware 鍵值來指派:

Route::get('admin/profile', ['middleware' => 'auth', function()
{
	//
}]);

Terminable 中介層

有些時候中介層需要在 HTTP 回應已被傳送到用戶端之後才執行,例如,Laravel 內建的「session」中介層,儲存 session 資料是在回應已被傳送到用戶端 之後 才執行。為了做到這一點,你需要定義中介層為「terminable」。

use Closure;
use Illuminate\Contracts\Routing\TerminableMiddleware;

class StartSession implements TerminableMiddleware {

	public function handle($request, Closure $next)
	{
		return $next($request);
	}

	public function terminate($request, $response)
	{
		// 儲存 session 資料...
	}

}

如你所見,除了定義 handle 方法之外,TerminableMiddleware 定義一個 terminate 方法。這個方法接收請求和回應。一旦定義了 terminable 中介層,你需要將它增加到 HTTP kernel 檔案的全域中介層清單列表中。