tp5.1 中間件

一、中間件是什麼?

中間件主要用於攔截或過濾應用的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對象,第二個參數是一個閉包。

中間件handle方法的返回值必須是一個Response對象。

在這個中間件中我們判斷當前請求的name參數等於think的時候進行重定向處理。否則,請求將進一步傳遞到應用中。要讓請求繼續傳遞到應用程序中,只需使用 $request 作爲參數去調用回調函數 $next 。

 

前置/後置中間件

中間件是在請求具體的操作之前還是之後執行,完全取決於中間件的定義本身。

下面是一個前置行爲的中間件

<?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
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章