laravel middleware 源码解析
middleware 的作用是啥?
我这保存着一份初学 php
原生 MCA
框架的代码让大家怀怀旧:
这个框架在访问网站 ⌈http://localhost/m=Home&c=Index&a=index
⌋ 时直接调用控制器方法,也就是直达目标。
然而,我们需要在到达控制器前或者调用控制器后执行一些需求。
middleware 在 Laravel 中应用的,比如权限中间件 ⌈处理请求前⌋:
<?php
namespace App\Http\Middleware;
// 权限中间件
class AdminAuth {
public function handle($request, Closure $next) {
if (!auth()->check()) {
return redirect(route('login'));
}
return $next($request);
}
}
跨域设置 [得到响应后]:
<?php
namespace App\Http\Middleware;
// 跨域设置
class Cors {
public function handle($request, Closure $next){
$response = $next($request);
$response->withHeaders([
'Access-Control-Allow-Origin' => '*',
..
]);
return $response;
}
}
为了能有一个大概的印象,上一图
中间件之间传递的是同一个 $request
对象
进入正题,一个重要的概念是,一个请求在未达到控制前,以及到达控制器时,层层中间件之间一直传递的都是同一个 $request
对象。哪怕在控制器中见到的自动注入的 $request
或者 request()
获得的实例。
下面先说一说控制器中 Request $request
为何是中间件过来的 $request
,这涉及服务容器的知识。
use Illuminate\Http\Request;
class IndexController extends Controller{
public function index(Request $request) {
return 200;
}
}
简单来说,在应用初始化时,已将 \Illuminate\Http\Request::class
alias 'request'
'request' => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],
也就是说容器在实例化 ⌈此处应该叫解析更恰当⌋ \Illuminate\Http\Request
时会先查找关联的键值 'request'
绑定在容器中的实例
那什么时候绑定的?下文中会介绍。由此,request()
得到的实例也就容易理解了
$request 对象
这得回到 index.php
Illuminate\Http\Request
类是 $request
实例的来源,capture()
是捕获,简单说就是从 $_GET $_POST $_SERVER $_COOKIE..
捕获 http 请求封装为对象。所以这一部分我们知道了
经过中间件
接下来是 http 内核 Kernel
处理 $request
了。
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
我们直接看 App\Http\Kernel::class
即可,其中定义了大量的中间件,可见中间件是 Http 核心的重要内容。
代码追踪 handle()
方法
到达核心代码
前文中提到的容器中 $request
实例是什么时候绑定到键值 'request'
的便在此处。
继续,Pipeline
翻译 ⌈管道⌋,从语义上,send($request)
是发送 $request
实例,through
是经过中间件,then
是然后分发路由,得到响应最后 return
。
然而 through
并非是执行了经过中间件的动作,源码中仅仅是向 Pipeline
中 ⌈注册⌋ 中间件
所以真正经过中间件的动作还是 then
方法。
Pipeline
接下来是代码较难懂的一部分了,也就是 then
方法。
理解中间件的原理最重要的是 array_reduce()
函数,可以参考下之前的文章 博客:middleware 原理
博客:laravel middleware 之 array_reduce 详解
整个中间件就是闭包套娃,像个洋葱,最里面的闭包是 ⌈最终目标⌋ 也就是控制器方法,最后传入参数 $request
所有的闭包一层层的抛开。
carry
翻译 ⌈运送⌋,middleware
的 handle
方法就是 carry()
方法中调用的:
每个中间件都将被封装成一个闭包,都有三个阶段,前置操作、传递请求、后置操作然后返回响应。控制器方法为最后目标,亦被封装为一个闭包。
本作品采用《CC 协议》,转载必须注明作者和本文链接
使用中间件可以缓解Api压力吗还是单纯为了优雅
其实我觉得中间件有点像Spring Aop的感觉哈