laravel 基礎教程 —— 中間件

中間件

簡介

HTTP 中間件為你的應用提供了一種便利的機制去過濾客戶端的請求,比如說laravel中自帶的用來驗證用戶是否已經認證的中間件,如果用戶的認證沒有通過,那么他將被重定向到登錄視圖。而如果用戶已經通過認證,那么他的請求就會被認證中間件通過,并將請求傳遞給應用。

中間件可以處理多種任務,不僅僅只是用于驗證用戶認證。比如你可以創建一個跨同源策略的中間件,用來處理每個請求在被響應前添加正確的響應頭,你還可以創造一個日志中間件,在應用被請求時優先記錄下請求信息。

Laravel框架本身提供了一些中間件,它們包括維護、認證、csrf保護、session等中間件,這些中間件都被定義在app\Http\Middleware目錄中。

定義中間件

為了創建一個新的中間件,你可以直接使用laravel提供的 make:middleware artisan命令:

php artisan make:middleware AgeMiddleware

這條命令會在app\Http\Middleware目錄下創建一個AgeMiddleware.php文件。我們創造這么一個中間件,讓只有年齡大于200的路由通過:

<?php

namespace App\Http\Middleware;

use Closure;

class AgeMiddleware {
  public function handle ($request, Closure $next) {
    if ($request->get('age') > 200) {
      return $next($request);
    }
    return redirect('home'); 
  }
}

你可以看到,如果請求中所提供的年齡小于等于200,請求將被直接返回一個重定向信息到客戶端,而如果年齡大于200,請求將被中間件繼續傳遞給應用。為了在中間件中將請求轉交給應用,你可以使用$next回調函數,并將$request傳遞進去。

你可以建立一系列的中間件來過濾客戶端的請求,這樣每一層中間件都可以檢查請求,如果通過,則將請求轉交到下一層,如果不通過則直接被駁回。

前行/后行 中間件

其實,在中間件中不僅僅可以定義前行中間件,即在請求被轉交到應用之前進行處理的中間件。

<?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;
  }
}

注冊中間件

全局中間件

如果你需要一個可以過濾所有請求的中間件,那么你可以注冊一個全局中間件。你需要先定義好中間件,然后在app/Http/kernel.php中的$middleware數組屬性中進行追加注冊。

分配中間件到路由

如果你想要分配中間件到特定的路由,那么你需要在app/Http/kernel.php文件中$routeMiddleware屬性中進行追加注冊,在這里你應該定義一個短字符的別名,以便于你在路由分配時快速指定。

// Within App\Http\Kernel Class...

protected $routeMiddleware = [
  'auth' => \App\Http\Middleware\Authenticate::class,
  'auth.basic' => \App\Http\Middleware\AuthenticateBasicAuth::class,
  'gust' => \App\Http\Middleware\RedirectIfAuthenticated::class,
  'throttle' => \App\Http\Middleware\ThrottleRequest::class,
];

一旦你的中間件被注冊在了kernel文件中,那么你就可以在定義路由時使用middleware選項進行中間件分配:

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

你可以通過這么做來分配多個中間件:

Route::get('/', ['middleware' => ['first', 'second'], function () {
  // 
}]);

當然laravel也允許你通過鏈式方法middleware去進行中間件分配:

Route::get('/', function () {
 // 
})->middleware(['first', 'second']);

事實上,你也可以使用完全類名來進行中間件分配:

use App\Http\Middleware\FooMiddleware;

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

中間件組

有時候你可能希望在分配路由時,可以通過一個別名來分配一系列的中間件到路由。你可以在kernel文件中使用$middlewareGroups屬性來進行注冊.

laravel自帶了webapi中間件組:

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,
    ],

    'api' => [
        'throttle:60,1',
        'auth:api',
    ],
];

一旦注冊了中間件組,你可以使用相同語法去分配中間件組到路由:

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

事實上,laravel自帶的web中間件組已經被默認啟用,所有在routes.php中被定義的路由都被分配了此中間件。你可以在RouteServiceProvider.php文件中進行修改.

帶參數的中間件

中間件也可以接收額外的自定義參數。比如說你可能需要一個中間件來驗證已認證的用戶的權限問題。你可能需要傳遞一個角色名稱參數來執行相應的行為.那么你需要創建一個RoleMiddleware來接收一個角色名稱作為額外的參數.
額外的參數將會被傳遞在$next參數之后:

<?php

namesapce App\Http\Middleware;

use Closure;

class RoleMiddleware {
  public function handle ($request, Closure $next, $role) {
    if (!$request->user()->hasRole($role)) {
      // Redirect...
    }

    return $next($request);
  }
}

帶參數的中間件在分配給路由時需要在中間件別名之后跟:來分割別名和參數,多個參數需要使用,分隔:

Route::post('post/{id}', ['middleware' => 'role:editor', function ($id) {
  // 
}]);

末端中間件

有時候你可能需要在響應被發送到客戶端之后繼續處理一些任務,比如說 session中間件在laravel中就是響應被發送出去之后才將session信息進行存儲操作。這時候你可以通過在中間件中添加terminate方法來定義一個末端中間件:

<?php

namespace Illuminate\Session\Middleware;

use Closure;

class StartSession {
  public function hanlde ($request, Closure $next) {
    return $next($request);
  }

  public function terminate($request, $response) {
    // Store the sessin data...
  }
}

terminate方法會接收請求和響應,一旦你定義了一個末端中間件,你應該在kernel文件中將其添加到全局中間件中.

每當中間件中的terminate方法被調用,laravel都會從服務容器中返回一個新的中間件實例,如果你想使用同一個實例,你應該將其注冊在服務容器中并使用singleton方法注冊.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 路由 路由(routing)就是通過互聯的網絡把信息從源地址傳輸到目的地址的活動。路由發生在OSI網絡參考模型中的...
    Dearmadman閱讀 2,874評論 2 9
  • 簡介 laravel 使實施認證的變得非常簡單,事實上,它提供了非常全面的配置項以適應應用的業務。認證的配置文件存...
    Dearmadman閱讀 6,184評論 2 13
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,933評論 18 139
  • 0.1配置1.模板繼承2.控制器3.git4.支付寶支付的流程5.路由6.中間件7.請求8.laravel 學習筆...
    云龍789閱讀 841評論 0 5
  • github地址,歡迎大家提交更新。 express() express()用來創建一個Express的程序。ex...
    Programmer客棧閱讀 2,590評論 0 1