> 從`5.1.6+`版本開始,正式引入中間件的支持。
中間件主要用于攔截或過濾應用的`HTTP`請求,并進行必要的業務處理。
## 定義中間件
可以通過命令行指令快速生成中間件
~~~
php think make:middleware Check
~~~
這個指令會 `application/http/middleware`目錄下面生成一個`Check`中間件。
~~~
<?php
namespace app\http\middleware;
class Check
{
public function handle($request, \Closure $next)
{
if ($request->param('name') == 'think') {
return redirect('index/think');
}
return $next($request);
}
}
~~~
中間件的入口執行方法必須是`handle`方法,而且第一個參數是`Request`對象,第二個參數是一個閉包。
>[danger] 中間件`handle`方法的返回值必須是一個`Response`對象。
在這個中間件中我們判斷當前請求的`name`參數等于`think`的時候進行重定向處理。否則,請求將進一步傳遞到應用中。要讓請求繼續傳遞到應用程序中,只需使用 `$request` 作為參數去調用回調函數 `$next` 。
>[info] 在某些需求下,可以使用第三個參數傳入額外的參數。
>
~~~
<?php
namespace app\http\middleware;
class Check
{
public function handle($request, \Closure $next, $name)
{
if ($name == 'think') {
return redirect('index/think');
}
return $next($request);
}
}
~~~
## 前置/后置中間件
中間件是在請求具體的操作之前還是之后執行,完全取決于中間件的定義本身。
下面是一個前置行為的中間件
~~~
<?php
namespace app\http\middleware;
class Before
{
public function handle($request, \Closure $next)
{
// 添加中間件執行代碼
return $next($request);
}
}
~~~
下面是一個后置行為的中間件
~~~
<?php
namespace app\http\middleware;
class After
{
public function handle($request, \Closure $next)
{
$response = $next($request);
// 添加中間件執行代碼
return $response;
}
}
~~~
來個比較實際的例子,我們需要判斷當前瀏覽器環境是在微信或支付寶
~~~
namespace app\http\middleware;
/**
* 訪問環境檢查,是否是微信或支付寶等
*/
class InAppCheck
{
public function handle($request, \Closure $next)
{
if (preg_match('~micromessenger~i', $request->header('user-agent'))) {
$request->InApp = 'WeChat';
} else if (preg_match('~alipay~i', $request->header('user-agent'))) {
$request->InApp = 'Alipay';
}
return $next($request);
}
}
~~~
然后在你的移動版的`module`里添加一個`middleware.php`文件
例如:`/path/application/mobile/middleware.php`
~~~
return [
app\http\middleware\InAppCheck::class,
];
~~~
然后在你的`controller`中可以通過`$this->request->InApp`獲取相關的值
## 注冊中間件
### 路由中間件
最常用的中間件注冊方式是注冊路由中間件
~~~
Route::rule('hello/:name','hello')
->middleware('Auth');
~~~
或者使用完整的中間件類名
~~~
Route::rule('hello/:name','hello')
->middleware(app\http\middleware\Auth::class);
~~~
支持注冊多個中間件
~~~
Route::rule('hello/:name','hello')
->middleware(['Auth', 'Check']);
~~~
`V5.1.7+`版本,你可以直接在應用配置目錄下的`middleware.php`中先預定義中間件(其實就是增加別名標識),例如:
~~~
return [
'auth' => app\http\middleware\Auth::class,
'check' => app\http\middleware\Check::class
];
~~~
然后直接在路由中使用中間件別名注冊
~~~
Route::rule('hello/:name','hello')
->middleware(['auth', 'check']);
~~~
`V5.1.8+`版本開始,可以支持使用別名定義一組中間件,例如:
~~~
return [
'check' => [
app\http\middleware\Auth::class,
app\http\middleware\Check::class
],
];
~~~
然后,直接使用下面的方式注冊中間件
~~~
Route::rule('hello/:name','hello')
->middleware('check');
~~~
支持對路由分組注冊中間件
~~~
Route::group('hello', function(){
Route::rule('hello/:name','hello');
})->middleware('Auth');
~~~
`V5.1.8+`版本開始支持對某個域名注冊中間件
~~~
Route::domain('admin', function(){
// 注冊域名下的路由規則
})->middleware('Auth');
~~~
如果需要傳入額外參數給中間件,可以使用
~~~
Route::rule('hello/:name','hello')
->middleware('Auth:admin');
~~~
如果使用的是常量方式定義,可以在第二個參數傳入中間件參數。
~~~
Route::rule('hello/:name','hello')
->middleware(Auth::class, 'admin');
~~~
如果需要定義多個中間件,使用數組方式
~~~
Route::rule('hello/:name','hello')
->middleware([Auth::class, 'Check']);
~~~
可以統一傳入同一個額外參數
~~~
Route::rule('hello/:name','hello')
->middleware([Auth::class, 'Check'], 'admin');
~~~
或者單獨指定中間件參數。
~~~
Route::rule('hello/:name','hello')
->middleware(['Auth:admin', 'Check:editor']);
~~~
### 使用閉包定義中間件
你不一定要使用中間件類,在某些簡單的場合你可以使用閉包定義中間件,但閉包函數必須返回`Response`對象實例。
~~~
Route::group('hello', function(){
Route::rule('hello/:name','hello');
})->middleware(function($request,\Closure $next){
if ($request->param('name') == 'think') {
return redirect('index/think');
}
return $next($request);
});
~~~
### 全局中間件
你可以在應用目錄下面定義`middleware.php`文件,使用下面的方式:
~~~
<?php
return [
\app\http\middleware\Auth::class,
'Check',
'Hello',
];
~~~
中間件的注冊應該使用完整的類名,如果沒有指定命名空間則使用`app\http\middleware`作為命名空間。
全局中間件的執行順序就是定義順序。可以在定義全局中間件的時候傳入中間件參數,支持兩種方式傳入。
~~~
<?php
return [
[\app\http\middleware\Auth::class, 'admin'],
'Check',
'Hello:thinkphp',
];
~~~
上面的定義表示 給`Auth`中間件傳入`admin`參數,給`Hello`中間件傳入`thinkphp`參數。
### 模塊中間件
`V5.1.8+`版本開始,支持模塊中間件定義,你可以直接在模塊目錄下面增加`middleware.php`文件,定義方式和應用中間件定義一樣,只是只會在該模塊下面生效。
### 控制器中間件
`V5.1.17+`版本開始,支持為控制器定義中間件。首先你的控制器需要繼承系統的`think\Controller`類,然后在控制器中定義`middleware`屬性,例如:
~~~
<?php
namespace app\index\controller;
use think\Controller;
class Index extends Controller
{
protected $middleware = ['Auth'];
public function index()
{
return 'index';
}
public function hello()
{
return 'hello';
}
}
~~~
當執行`index`控制器的時候就會調用`Auth`中間件,一樣支持使用完整的命名空間定義。
如果需要設置控制器中間的生效操作,可以如下定義:
~~~
<?php
namespace app\index\controller;
use think\Controller;
class Index extends Controller
{
protected $middleware = [
'Auth' => ['except' => ['hello'] ],
'Hello' => ['only' => ['hello'] ],
];
public function index()
{
return 'index';
}
public function hello()
{
return 'hello';
}
}
~~~
## 中間件向控制器傳參
可以通過給請求對象賦值的方式傳參給控制器(或者其它地方),例如
~~~
<?php
namespace app\http\middleware;
class Hello
{
public function handle($request, \Closure $next)
{
$request->hello = 'ThinkPHP';
return $next($request);
}
}
~~~
> 注意,傳遞的變量名稱不要和`param`變量有沖突。
然后在控制器的方法里面可以直接使用
~~~
public function index(Request $request)
{
return $request->hello; // ThinkPHP
}
~~~
- 序言
- 基礎
- 安裝
- 開發規范
- 目錄結構
- 配置
- 架構
- 架構總覽
- 入口文件
- URL訪問
- 模塊設計
- 命名空間
- 容器和依賴注入
- Facade
- 鉤子和行為
- 中間件
- 路由
- 路由定義
- 變量規則
- 路由地址
- 閉包支持
- 路由參數
- 路由緩存
- 跨域請求
- 注解路由
- 路由分組
- MISS路由
- 資源路由
- 快捷路由
- 路由別名
- 路由綁定
- 域名路由
- URL生成
- 控制器
- 控制器定義
- 前置操作
- 跳轉和重定向
- 空操作和空控制器
- 分層控制器
- 資源控制器
- 控制器中間件
- 請求
- 請求對象
- 請求信息
- 輸入變量
- 請求類型
- HTTP頭信息
- 偽靜態
- 參數綁定
- 請求緩存
- 響應
- 響應輸出
- 響應參數
- 重定向
- 文件下載
- 數據庫
- 連接數據庫
- 查詢構造器
- 查詢數據
- 添加數據
- 更新數據
- 刪除數據
- 查詢表達式
- 鏈式操作
- where
- table
- alias
- field
- strict
- limit
- page
- order
- group
- having
- join
- union
- distinct
- lock
- cache
- comment
- fetchSql
- force
- partition
- failException
- sequence
- 聚合查詢
- 時間查詢
- 高級查詢
- 視圖查詢
- JSON字段
- 子查詢
- 原生查詢
- 查詢事件
- 獲取器
- 事務操作
- 監聽SQL
- 存儲過程
- 數據集
- 分布式數據庫
- 模型
- 定義
- 新增
- 更新
- 刪除
- 查詢
- JSON字段
- 獲取器
- 修改器
- 搜索器
- 數據集
- 自動時間戳
- 只讀字段
- 軟刪除
- 類型轉換
- 數據完成
- 查詢范圍
- 模型輸出
- 模型事件
- 模型關聯
- 一對一關聯
- 一對多關聯
- 遠程一對多
- 多對多關聯
- 多態關聯
- 關聯預載入
- 關聯統計
- 關聯輸出
- 視圖
- 視圖渲染
- 視圖賦值
- 視圖過濾
- 模板引擎
- 模板
- 變量輸出
- 使用函數
- 運算符
- 原樣輸出
- 模板注釋
- 模板布局
- 模板繼承
- 包含文件
- 輸出替換
- 標簽庫
- 內置標簽
- 循環標簽
- 比較標簽
- 條件判斷
- 資源文件加載
- 標簽嵌套
- 原生PHP
- 定義標簽
- 標簽擴展
- 錯誤和日志
- 異常處理
- 日志處理
- 調試
- 調試模式
- Trace調試
- 性能調試
- SQL調試
- 變量調試
- 遠程調試
- 驗證
- 驗證器
- 驗證規則
- 錯誤信息
- 驗證場景
- 路由驗證
- 內置規則
- 獨立驗證
- 靜態調用
- 表單令牌
- 雜項
- 緩存
- Session
- Cookie
- 多語言
- 分頁
- 上傳
- 命令行
- 啟動內置服務器
- 查看版本
- 自動生成目錄結構
- 創建類庫文件
- 生成類庫映射文件
- 清除緩存文件
- 生成配置緩存文件
- 生成數據表字段緩存
- 生成路由映射緩存
- 輸出路由定義
- 自定義指令
- 擴展庫
- 驗證碼
- 圖像處理
- Time
- 數據庫遷移工具
- Swoole
- Workerman
- MongoDb
- 單元測試
- 安全和性能
- 安全建議
- 優化建議
- 附錄
- 助手函數
- 升級指導
- 更新日志