laravel middleware 源码解析

middleware 的作用是啥?

我这保存着一份初学 php 原生 MCA 框架的代码让大家怀怀旧:

middleware

这个框架在访问网站 ⌈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;
    }
}

为了能有一个大概的印象,上一图

middleware

中间件之间传递的是同一个 $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' 绑定在容器中的实例

middleware

那什么时候绑定的?下文中会介绍。由此,request() 得到的实例也就容易理解了

middleware

$request 对象

这得回到 index.php

middleware

Illuminate\Http\Request 类是 $request 实例的来源,capture() 是捕获,简单说就是从 $_GET $_POST $_SERVER $_COOKIE.. 捕获 http 请求封装为对象。所以这一部分我们知道了

middleware

经过中间件

接下来是 http 内核 Kernel 处理 $request 了。

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

我们直接看 App\Http\Kernel::class 即可,其中定义了大量的中间件,可见中间件是 Http 核心的重要内容。

laravel middleware 源码解析

代码追踪 handle() 方法

middleware

middleware

到达核心代码

middleware

前文中提到的容器中 $request 实例是什么时候绑定到键值 'request' 的便在此处。
继续,Pipeline 翻译 ⌈管道⌋,从语义上,send($request) 是发送 $request 实例,through 是经过中间件,then 是然后分发路由,得到响应最后 return
然而 through 并非是执行了经过中间件的动作,源码中仅仅是向 Pipeline 中 ⌈注册⌋ 中间件

middleware

所以真正经过中间件的动作还是 then 方法。

Pipeline

接下来是代码较难懂的一部分了,也就是 then 方法。

middleware

理解中间件的原理最重要的是 array_reduce() 函数,可以参考下之前的文章 博客:middleware 原理

整个中间件就是闭包套娃,像个洋葱,最里面的闭包是 ⌈最终目标⌋ 也就是控制器方法,最后传入参数 $request 所有的闭包一层层的抛开。

carry 翻译 ⌈运送⌋,middlewarehandle 方法就是 carry() 方法中调用的:

middleware

middleware

每个中间件都将被封装成一个闭包,都有三个阶段,前置操作、传递请求、后置操作然后返回响应。控制器方法为最后目标,亦被封装为一个闭包。

再聊 laravel middleware

本作品采用《CC 协议》,转载必须注明作者和本文链接
welcome come back
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 3

使用中间件可以缓解Api压力吗还是单纯为了优雅

3周前 评论
php_yt (楼主) 3周前

其实我觉得中间件有点像Spring Aop的感觉哈

3周前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
未填写
文章
79
粉丝
20
喜欢
129
收藏
306
排名:358
访问:2.5 万
私信
所有博文
社区赞助商