本文目录导读:

在 PHP 中,中间件的执行通常遵循 洋葱模型(Onion Model) 或 管道模式(Pipeline Pattern),核心思想是:请求依次通过中间件层,每一层可以决定是否继续传递请求(或处理响应返回)。
下面我会从基础概念到手写实现、再到主流框架(Laravel/ThinkPHP)的对比来说明。
核心执行机制:闭包传递
绝大多数 PHP 中间件的核心代码只有一句话:
// 伪代码核心: next 是一个回调,指向下一个中间件或最终处理 return $next($request);
- 当一个中间件调用
$next($request)时,程序会进入下一个中间件。 - 当所有中间件都执行完后,最终处理(路由/控制器)返回响应,响应再原路返回经过每个中间件的后续代码。
手写一个简单的中间件运行机制
为了彻底搞懂,我们可以手动实现:
步骤 1:定义中间件接口
interface Middleware {
public function handle($request, \Closure $next);
}
步骤 2:实现几个中间件
class AuthMiddleware implements Middleware {
public function handle($request, \Closure $next) {
echo "Auth 中间件:开始\n";
// 条件不通过,直接返回,不再向下
// if(!$request->hasToken) return "403 未授权";
$response = $next($request);
echo "Auth 中间件:结束\n";
return $response;
}
}
class LogMiddleware implements Middleware {
public function handle($request, \Closure $next) {
echo "Log 中间件:开始\n";
$response = $next($request);
echo "Log 中间件:结束\n";
return $response;
}
}
步骤 3:构建管道执行
class Pipeline {
private $middlewares = [];
public function add(Middleware $middleware) {
$this->middlewares[] = $middleware;
}
public function run($request, \Closure $finalHandler) {
// 关键:从最后一个中间件往前构建闭包链
$stack = $finalHandler;
// 反转数组,从最后一个中间件开始包裹
foreach(array_reverse($this->middlewares) as $middleware) {
$stack = function($request) use ($middleware, $stack) {
return $middleware->handle($request, $stack);
};
}
// 执行最终构建的闭包
return $stack($request);
}
}
步骤 4:测试
$pipeline = new Pipeline();
$pipeline->add(new AuthMiddleware());
$pipeline->add(new LogMiddleware());
$request = "some request data";
$result = $pipeline->run($request, function($req) {
echo "--- 核心业务处理 ---\n";
return "处理结果";
});
echo "\n最终返回: " . $result;
输出结果:
Auth 中间件:开始
Log 中间件:开始
--- 核心业务处理 ---
Log 中间件:结束
Auth 中间件:结束
最终返回: 处理结果
顺序执行逻辑:
Auth -> Log -> 核心 -> Log -> Auth这完全符合洋葱模型的 先入后出(Stack) 特性。
主流框架的实现对比
Laravel 中间件
Laravel 使用 Symfony 的 HttpKernelInterface + 管道模式。
- 定义:
app/Http/Kernel.php中的$middleware和$routeMiddleware。 - 执行流程:
// 核心代码片段(简化)
$response = (new Pipeline($this->app))
->send($request)
->through($middleware)
->then(function ($request) use ($router) {
return $router->dispatch($request);
});
- 单个中间件:
class CheckAge {
public function handle($request, \Closure $next) {
if ($request->age < 18) {
return redirect('home'); // 中断
}
return $next($request); // 继续
}
}
Laravel 还支持中间件组(web/api)、Terminable Middleware(请求结束后执行清理)。
ThinkPHP 6 中间件
ThinkPHP的中间件机制类似,定义在 config/middleware.php。
- 定义:
class Hello {
public function handle($request, \Closure $next) {
// 前置操作
$response = $next($request);
// 后置操作
return $response;
}
}
- 调用时通过
think\Pipeline类实现,和手写原理基本一致。
中间件的常见应用场景(前端视角)
如果你的工作涉及 PHP 后端,中间件最常用在以下场景:
| 场景 | 中间件作用 | 原生/框架解决方案 |
|---|---|---|
| 用户认证 | 未登录跳转登录页 | auth中间件(Laravel)think\middleware\AllowCrossDomain |
| CORS跨域 | 添加 Access-Control-* 头 |
App\Http\Middleware\Cors |
| 限流 | 防止DDOS/刷接口 | throttle:60,1(60次/分钟) |
| 请求日志 | 记录所有API请求参数和时间 | 自定义中间件 |
| 响应压缩 | gzip | \App\Http\Middleware\CompressResponse |
执行流程总结
[请求 进来]
↓
中间件1 开始(前置代码)
↓ 调用 $next($request)
中间件2 开始(前置代码)
↓ 调用 $next($request)
...
最终控制器/业务处理 (返回响应)
...
↑ $response 返回
中间件2 结束(后置代码)
↑ $response 返回
中间件1 结束(后置代码)
↑
[响应 返回给客户端]
关键点:
$next($request)就像 “放行”按钮 —— 不调用就卡住(中断请求)。- 响应的后置处理代码的执行顺序和中间件添加顺序相反(栈的特性)。
- 框架通常用
Pipeline类将多个中间件压扁成一个闭包来依次执行。
PHP 中间件的核心思想就是 装饰器模式 + 闭包传递,通过把行为分层包装,实现了高度可解耦的请求处理流程。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播