中间件
6.0对于中间件的重视程度可以从核心内置了一些中间件看出端倪,几乎到了无中间件不开发的程度。中间件主要用于拦截或过滤应用的HTTP请求,并进行必要的数据处理或者业务流程。控制台指令执行是不会执行中间件的。
可以通过指令快速生成中间件
php think make:middleware Hello
会自动生成一个app\middleware\Hello中间件
<?php
declare (strict_types = 1);
namespace app\middleware;
class Hello
{
/**
* 处理请求
*
* @param \think\Request $request
* @param \Closure $next
* @return Response
*/
public function handle($request, \Closure $next)
{
//
}
}
中间件的执行入口就是handle方法,并且该方法必须返回一个Response对象。如果你的中间件需要在请求结束后执行某些操作,可以增加end方法定义,用于请求结束回调。
<?php
declare (strict_types = 1);
namespace app\middleware;
class Hello
{
/**
* 处理请求
*
* @param \think\Request $request
* @param \Closure $next
* @return Response
*/
public function handle($request, \Closure $next)
{
}
public function end(\think\Response $response)
{
}
}
注意,在end方法里面不能有任何的响应输出。因为回调触发的时候请求响应输出已经完成了。
如果你要生成指定命名空间的中间件,可以在创建的时候输入完整的类名
php think make:middleware app\index\middleware\Hello
前置和后置
我们知道中间件的作用是用于拦截当前HTTP请求,进行相应的数据处理,数据处理的时机不同就产生了前置和后置中间件的概念。
如果你是希望在某个操作方法执行之前进行的数据处理或者业务流程,那么应该使用前置中间件,如果你希望在操作方法执行完毕后进行数据处理或者业务流程,那么就应当使用后置中间件,当然,你可以同时进行前置和后置中间件的处理,下面是一个前置和后置中间件的定义示例:
<?php
namespace app\middleware;
class Hello
{
public function handle($request, \Closure $next)
{
// 添加前置中间件执行代码
$response = $next($request);
// 添加后置中间件执行代码
return $response;
}
}
注册中间件
中间件按照生效范围及执行顺序依次为全局中间件、应用中间件、路由中间件和控制器中间件,这四个中间件分组完全独立执行,同一个分组内的中间件不会重复执行。
全局中间件可以在app/middleware.php文件中定义(注意和中间件别名定义config/middleware.php配置文件的区别),定义方式为:
return [
\think\middleware\SessionInit::class,
\app\middleware\Hello::class,
];
执行中间件的时候会按照定义的顺序依次执行。如果你的中间件需要在多个场合下使用,可以给中间件定义别名,方便简化调用。
在config/middleware.php配置文件中定义:
return [
'alias' => [
'hello' => \app\middleware\Hello::class,
'session' => \think\middleware\SessionInit::class,
],
];
现在,你可以把全局中间件定义文件简化为:
return [
'session',
'hello',
];
如果是多应用模式,还可以给某个应用定义应用中间件,(例如index则是在app/index/middleware.php中单独定义中间件即可),定义方式和全局中间件一致,区别在于应用中间件仅在当前应用下才会执行。所以你需要针对不同的业务使用不同的中间件。
由于中间件的执行流程设计,在全局中间件或者应用中间件中是不能获取当前的控制器和操作的,如果你需要获取控制器和操作必须使用路由中间件或者控制器中间件。
路由中间件是在路由检测匹配后执行的中间件,通常是路由注册的时候定义,例如:
Route::rule('hello/:name', 'index/hello')->middleware(Auth::class);
通常我们会定义在路由分组上,例如:
Route::group('user', function() {
Route::rule(':name', 'user/getInfo');
})->middleware(Auth::class);
如果你希望对所有的路由都定义中间件,那么可以直接在应用的路由配置文件(例如app/index/config/route.php)中定义:
'middleware' => [
Auth::class,
],
这样无论路由是否匹配,最终都会执行配置的(路由全局)中间件。
控制器中间件是仅执行到控制器操作方法的时候才会执行的中间件,你只需要在控制器类中增加middleware属性即可。
namespace app\controller;
use app\middleware\Auth;
class User
{
protected $middleware = [Auth::class];
public function getInfo()
{
}
}
控制器中间件可以设置排除某些操作或者仅仅用于某些操作
<?php
namespace app\controller;
use app\middleware\Auth;
use app\middleware\Hello;
class Index
{
protected $middleware = [
Auth::class => ['except' => 'hello,login' ],
Hello::class => ['only' => 'hello' ],
];
public function index()
{
return 'index';
}
public function login()
{
return 'login';
}
public function hello()
{
return 'hello';
}
}
中间件传参
可以通过给请求对象赋值的方式传参给控制器(或者其它地方),例如
<?php
namespace app\middleware;
class Hello
{
public function handle($request, \Closure $next)
{
$request->hello = 'ThinkPHP';
return $next($request);
}
}
然后在控制器的方法里面可以直接使用
public function index(Request $request)
{
return $request->hello; // ThinkPHP
}
如果需要在执行中间件的时候传入指定的额外参数,可以使用:
Route::rule('hello/:name','hello')
->middleware('auth', 'admin');
在中间件定义的时候增加参数即可
<?php
namespace app\middleware;
class Auth
{
public function handle($request, \Closure $next, $type)
{
if ('admin' == $type) {
// 管理员
} elseif ('guest' == $type) {
// 游客
}
return $next($request);
}
}
发表评论