ThinkPHP6的前置中间件和后置中间件的区别,中间件解决跨域问题的方案
ThinkPHP6的中间件主要用于拦截或过滤应用的HTTP请求,并进行必要的业务处理。日常开发中可以灵活关闭,包括Session功能、请求缓存和多语言功能。其中中间件有“前置中间件”、“后置中间件”,两者有和区别呢?
一、定义的区别。
从官网手册中不难发现,前置中间件和后置中间件定义就不同,我们看下面。
前置中间件定义:
<?php
namespace app\middleware;
class Before
{
public function handle($request, \Closure $next)
{
// 添加中间件执行代码
return $next($request);
}
}
后置中间件:
<?php
namespace app\middleware;
class After
{
public function handle($request, \Closure $next)
{
$response = $next($request);
// 添加中间件执行代码
return $response;
}
}
大家仔细一看发现,说到底两者在定义的时候就是执行代码和$next($request)
的顺序问题,也正是这个顺序才是前置中间件与后置中间件的关键所在。
二、$request不同。
通过可以分别在前置和后置中间件打印如下代码:
halt($request);
经过仔细对比发现,前置中间件中的控制器和方法是空的,后置中间件却可以得到控制器名称和方法。所以如果我们想获取当前访问的控制器以及方法,就需要用后置中间件解决。
三、中间件拦截登录场景。
先看一下官网关于中间件的定义:中间件主要用于拦截或过滤应用的 HTTP 请求,并进行必要的业务处理。
看了官网的定义,大家可能会想到,用中间件去做登录拦截真的是再好不过的呀。但是是用前置还是后置中间件呢?
<?php
namespace app\middleware;
class After
{
public function handle($request, \Closure $next)
{
$response = $next($request);
// 添加中间件执行代码
if(empty('session')){
echo '登录不合法';
//跳转到登录页面
}
return $response;
}
}
后台首页:
public function index(){
echo '后台首页';
}
执行结果会发现,在登录跳转前我们依然可以执行到index方法,并且可以把内容输出。
因此,后置中间件不能使用在登录场景,前置中间件是拦截登录最佳的解决方案,这个时候还需要判断当前访问是不是登录,如果是登录的话,会出现多次重定向,所以这个小伙伴们一定要做好处理。
以上就是前置后置中间件的相关介绍,在实际项目中,根据我们的实际业务逻辑来判断是用前置还是后置中间件。
另外,还可以利用中间件来解决跨域问题。
首先cors跨域复杂请求有一个预请求,第一个请求不管,处理第二请求就行,具体如下:
middleware.php 代码
<?php
// 全局中间件定义文件
return [
// 全局请求缓存
// \think\middleware\CheckRequestCache::class,
// 多语言加载
// \think\middleware\LoadLangPack::class,
// Session初始化
// \think\middleware\SessionInit::class
// 跨域
\app\api\middleware\Allow::class
// \think\middleware\AllowCrossDomain::class
];
Allow.php 代码
<?php
use think\Response;
namespace app\api\middleware;
class Allow
{
public function handle($request, \Closure $next)
{
// 处理跨域
header('Access-Control-Allow-Origin: *');
header('Access-Control-Max-Age: 1800');
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE');
header('Access-Control-Allow-Headers: Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With, access-token');
// 第一次预请求不管
if (strtoupper($request->method()) == "OPTIONS") {
exit;
}
// 处理跨域
// 后置中间件
$response = $next($request);
return $response;
}
/**
* 中间件结束调度
* @param \think\Response $response
* @return void
*/
public function end(\think\Response $response)
{
}
}
需要注意的是:自定义header参数不要用下划线,类似access-token,accessToken就行。