深入解析Laravel的中介軟體

it阿布發表於2020-08-11

Laravel 中介軟體是什麼?

簡而言之,中介軟體在 laravel 中的作用就是過濾 HTTP 請求,根據不同的請求來執行不同的邏輯操作。

我們可以通過中介軟體實現以下功能:

  • 指定某些路由
  • 設定 HTTP 響應頭
  • 記錄請求
  • 過濾請求的引數
  • 決定是否啟用站點維護模式
  • 響應前後做一些必要的操作

自定義中介軟體

命令列執行下面的簡單命令,就可以輕鬆建立一個新的中介軟體

php artisan make:middleware <MiddlewareName>
//MiddlewareName 就是你要建立的中介軟體的名字

執行上面的命令,Laravel 會在app/Http/Middleware目錄下自動建立一個只包含handle方法的中介軟體。

<?php
namespace App\Http\Middleware;
use Closure;
class RedirectIfSuperAdmin
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        return $next($request);
    }
}

在中介軟體被呼叫的時候,handle方法就會執行。這裡需要注意的是 handle 方法預設有兩個引數$request$next$request用來接受應用的請求組求,$next將請求傳遞給應用程式。這兩個引數是handle必不可少的!中介軟體也包括前置中介軟體和後置中介軟體。

“前置中介軟體” 顧名思義在將請求轉發到應用程式之前處理一些邏輯。 另一方面,在中介軟體之後,在應用程式處理了請求並生成響應之後執行。

前置中介軟體:

<?php
namespace App\Http\Middleware;
use Closure;
class RedirectIfSuperAdmin
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        //你的邏輯就在這裡
        return $next($request);
    }
}

後置中介軟體:

<?php
namespace App\Http\Middleware;
use Closure;
class RedirectIfSuperAdmin
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        //你的邏輯就在這裡 例如 重定向到  `/`

        return $response;
    }
}

中介軟體的類別

  • 全域性中介軟體
  • 路由中介軟體

全域性中介軟體針對命中應用程式的每個請求執行。 Laravel 自帶了大多數這些中介軟體例如ValidatePostSizeTrimStrings,CheckForMaintenanceMode等等.

路由中介軟體僅在它們所連線的路由上執行
例如redirectIfAuthenticated.

註冊中介軟體

建立的任何中介軟體都必須註冊,因為這是 Laravel 知道存在的唯一方式。 要註冊中介軟體,只需開啟名為kernel.php的檔案,該檔案位於 Http 資料夾中,如下所示:
在這裡插入圖片描述
此檔案包含預設 Laravel 提供的所有已註冊中介軟體的列表。 它包含三個主要的中介軟體組$middleware$middlewareGroups和 $routeMiddleware

<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
    /**
     * 應用程式的全域性HTTP中介軟體。
     *
     * 這些中介軟體在應用程式的每個請求期間執行。
     *
     * @var array
     */
    protected $middleware = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        \App\Http\Middleware\TrustProxies::class,
    ];
    /**
     * 應用程式的路由中介軟體組.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];
    /**
     * 應用程式的路由中介軟體.
     *
     * 可以將這些中介軟體分配給組或單獨使用。
     *
     * @var array
     */
    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,
        //the just created middlware
        'superadmin' => \App\Http\Middleware\RedirectIfSuperAdmin::class, 
    ];
}

$middleware陣列包含全域性中介軟體,它執行應用程式的每個 HTTP 請求,所以如果你想為每個請求執行一箇中介軟體,你應該在這裡註冊它。$middlewareGroups使得可以在組中註冊中介軟體,從而更容易通過使用組名將大量中介軟體附加到路由。$routeMiddleware 陣列包含各個註冊的路由中介軟體。

分配中介軟體

有兩個主要方法可以把註冊好的中介軟體應用到路由中。

  • 通過控制器的構造方法
  • 通過路由

通過構造方法分配中介軟體

通過構造方法分配中間有很大的靈活性,它提供了兩個重要的方法except($parameters)only($parameters),這兩個方法可以允許或阻止中介軟體應用到控制器中的輔助方法。不使用這兩個方法,中介軟體將使用與控制器的每個方法。

<?php
use Illuminate\Http\Request;

class ForumController extends Controller
{

    public function __construct(){
      /**in this case the middleware named auth is applied
       to every single function within this controller
       */
        $this->middleware('auth');
    }

    public function viewForum(){

      return view('index');
    }

    public function edit($id){

    }

    public function delete($id){

    }

}

使用exceptonly方法我們可以選擇把中介軟體應用到指定方法。如下所示:

<?php
use Illuminate\Http\Request;

class ForumController extends Controller
{

    public function __construct(){
      /**the authentication middleware here applies to all functions but
       viewForums() and viewForumDetails() and the opposite of this happens
       when you use only()
       */
        $this->middleware('auth')->except(['viewForums', 'viewForumDetails']);
    }

    public function viewForums(){

      return view('index');
    }

    public function edit($id){

    }

    public function delete($id){

    }

    public function viewForumDetails(){

    }
}

通過路由分配中介軟體

如果註冊的中介軟體可以直接附加到路由,如下所示:

<?php
//方法 1
Route::get('admin/profile', function () {
  //action
})->middleware('auth');

/**方法 2
或者像這樣使用完全限定的類名:
*/
use App\Http\Middleware\CheckAge;

Route::get('admin/profile', function () {
    // action
})->middleware(CheckAge::class);

//方法 3
Route::group(['middleware' => ['web']], function () {
    //action
});

N:B 中介軟體組可以像單箇中介軟體一樣分配給路由

中介軟體引數

其他引數可以傳遞給中介軟體。 典型示例是將每個使用者 ID 分配給角色,中介軟體檢查使用者的角色以確定是否有權訪問所請求的 URI。 引數可以傳遞給中介軟體,如下所示:

<?php
//方法1 (Through route)
Route::get('admin/profile', function () {
  //action
})->middleware('auth:<role>'); //<role> 這裡應該被使用者想要傳遞的任何引數替換。

//方法2 (Through a controller)
use Illuminate\Http\Request;

class ForumController extends Controller
{

    public function __construct(){
        $this->middleware('auth:<role>');
    }
  }

通過用逗號分隔每個引數,可以將多個引數傳遞給中介軟體。

<?php
Route::get('admin/profile', function () {
  //action
})->middleware('auth:<role>,<age>,<country>'); //<role>, <age>, <country> 這裡應該被使用者想要傳遞的任何引數替換。

這些引數在$next變數之後傳遞給中介軟體的 handle 函式

<?php
class RedirectIfSuperAdmin
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next, $role, $age, $country)
    {   
        //使用解析引數的中介軟體邏輯
        return $next($request);
    }
}

摘要

要建立中介軟體,請執行以下過程

  • 使用 artisan 命令建立中介軟體 php artisan make:middleware 中介軟體名.
  • 在 app→Http 資料夾中的 kernel.php 中註冊中介軟體
  • 在建立的中介軟體中編寫邏輯
  • 將中介軟體分配給路由或控制器

結論

Laravel 中介軟體可以更輕鬆地保護我們的路由,過濾輸入並完成許多其他工作,而無需編寫如此多的邏輯。 檢視官方 Laravel 文件 這裡 瞭解中介軟體的更多功能,最重要的是練習。


相關文章