中间件的实现原理

           用过express的同学都知道,一个HTTP请求的完成就是经过若干中间件完成的,中间件是一个可访问请求对象(req)和响应对象(res)的函数,在 Express 应用的请求-响应循环里,下一个内联的中间件通常用变量 next 表示。

       那么现在我先上一道我面试中遇到的一道题,考的就是中间件的一个实现思路。当然如果你知道express,会更好地帮助你理解。

       

     function fun1(ctx, next) {
         ctx.count++;
         console.log(ctx.count);
         next();
     }
     function fun2(ctx, next) {
         ctx.count++;
         console.log(ctx.count);
         next();
     }
     function  fun3(ctx, next) {
         ctx.count++;
         console.log(ctx.count);
         next();
     }
     compose([fun1, fun2, fun3])({count: 1});
      
这道题的是让你实现一个compose,使得compose([fun1, fun2, fun3])({count: 1})调用后,使得fun1 fun2 fun3依次执行,比如在fun1里面当
next被调用时,就会把控制权交给下一个中间件函数,fun1的下一个中间件函数fun2就会被执行,{count:1}是传入的context,中间件函数就是
依次对context对象进行处理。

     我的compose实现思路很简单,如下

 function compose(arr){
         index = 0;
         len = arr.length;
         return function (ctx) {
             function next() {
                 index++;
                 if(index >= len) return;
                 arr[index](ctx, next);
             }
             arr[index](ctx, next);
         }
     }

这样输出的结果是 2 3 4,和预期相符

下面我们来验证一个这个解法对不对。

测试一:如果在某个中间函数体中,用户没有调用next,则不会继续调用下个中间件函数。

function fun1(ctx, next) {
         ctx.count++;
         console.log(ctx.count);
         next();
     }
     function fun2(ctx, next) {
         ctx.count++;
         console.log(ctx.count);
//         next();           
     }
     function  fun3(ctx, next) {
         ctx.count++;
         console.log(ctx.count);
         next();
     }
     compose([fun1, fun2, fun3])({count: 1});
如上在fun2中没用调用next ,则输出为2 3,和预期相符

测试二:如果next的调用在异步环境里面,则下一个中间件函数必须等上一个中间件函数的next真正被调用(即使是异步)时才会执行。

function fun1(ctx, next) {
         ctx.count++;
         console.log(ctx.count);
         next();
     }
     function fun2(ctx, next) {
         ctx.count++;
         console.log(ctx.count);
         setTimeout(function () {
             next();
         },1000);
     }
     function  fun3(ctx, next) {
         ctx.count++;
         console.log(ctx.count);
         next();
     }
     compose([fun1, fun2, fun3])({count: 1});
如上,在fun2中1s后才调用next,输出为 2 3 然后一秒后输出4 ,符合预期。

当然这是一个最简单的中间件实现思路,在express中间件中远比这复杂,但是这可以考察你解决问题的思路。





     

ThinkPHP 中间件的工作原理实现机制是其框架灵活性与可扩展性的重要体现。中间件本质上是一个请求与响应之间的处理层,允许开发者在请求到达控制器之前或响应发送之前执行特定逻辑。这一机制特别适用于权限验证、日志记录、CORS 处理等通用任务。 ### 中间件的加载与注册 在 ThinkPHP6 中,中间件的加载通常通过 `app/middleware.php` 文件完成,该文件用于导入全局中间件[^3]。框架通过以下代码将中间件注册到应用实例中: ```php $this->app->middleware->import(include $this->app->getBasePath() . 'middleware.php'); ``` 上述代码会加载 `middleware.php` 文件中定义的中间件,并将其导入到应用的中间件栈中[^4]。 ### 中间件的执行流程 中间件的执行分为**前置中间件**和**后置中间件**两种形式。前置中间件通常用于在请求到达控制器之前进行预处理,例如身份验证或请求过滤。后置中间件则用于在响应生成之后、发送给客户端之前进行后处理,例如添加响应头或记录日志。 以下是一个典型的前置中间件示例: ```php class Check { public function handle($request, \Closure $next) { if (true) { return json('middle'); } return $next($request); } } ``` 如果条件满足(例如验证失败),该中间件可以提前返回响应;否则,调用 `$next($request)` 将请求传递给下一个中间件或控制器[^5]。 对于后置中间件,逻辑稍有不同: ```php class Logging { public function handle($request, \Closure $next) { $response = $next($request); if (true) { return json('middle'); } return $response; } } ``` 该中间件会在请求处理完成后对响应进行修改或记录[^5]。 ### 中间件的绑定与优先级 中间件可以绑定到特定的路由或作为全局中间件使用。例如,以下代码将 `Check` 和 `Auth` 中间件绑定到 `login` 路由: ```php Route::rule('login', 'api/v1.Login/getLinkData')->middleware(['check', 'auth']); ``` 中间件的执行顺序遵循定义的顺序,`check` 会优先于 `auth` 执行[^5]。 ### 中间件的设计哲学 从设计角度来看,中间件实现体现了 ThinkPHP 的模块化与可插拔特性。中间件机制简化了业务逻辑与框架核心的耦合,使得开发者可以专注于功能实现而不必修改框架核心代码[^2]。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值