本文目录导读:

在 PHP 项目中,中间件(Middleware)是一种非常流行的设计模式,主要用于在请求到达控制器之前或响应返回给客户端之前执行一些预处理或后处理逻辑。
根据你的项目是传统框架(如 Laravel、ThinkPHP) 还是原生 PHP,使用方式有所不同,下面分别介绍。
在主流 PHP 框架中使用中间件
A. Laravel (最典型的例子)
Laravel 的中间件是核心功能之一,常用于身份验证、日志记录、CORS、CSRF 保护等。
步骤 1:创建中间件
php artisan make:middleware CheckAge
这会在 app/Http/Middleware/ 目录下生成 CheckAge.php 文件。
步骤 2:编写中间件逻辑
<?php
namespace App\Http\Middleware;
use Closure;
class CheckAge
{
public function handle($request, Closure $next)
{
// 预处理逻辑(请求进入控制器前)
if ($request->age < 18) {
return redirect('home'); // 拦截请求
}
// 继续执行下一个中间件或控制器
$response = $next($request);
// 后处理逻辑(控制器返回响应后)
// 修改响应头
$response->headers->set('X-Framework', 'Laravel');
return $response;
}
}
步骤 3:注册中间件
- 全局中间件:在
app/Http/Kernel.php的$middleware数组中注册。 - 路由中间件:在
$routeMiddleware数组中起别名。
// app/Http/Kernel.php
protected $routeMiddleware = [
'check.age' => \App\Http\Middleware\CheckAge::class,
];
步骤 4:使用中间件
// 在路由中使用
Route::get('/admin/profile', function () {
// ...
})->middleware('check.age');
// 或在控制器中使用
public function __construct()
{
$this->middleware('check.age');
}
B. ThinkPHP 6.0+
ThinkPHP 6 引入了类似 Laravel 的中间件机制。
步骤 1:定义中间件
在 app/middleware.php 配置文件中注册,或在 app/middleware 目录下创建类。
<?php
namespace app\middleware;
class Check
{
public function handle($request, \Closure $next)
{
// 预处理
if ($request->param('token') !== 'abc') {
return json(['error' => 'Unauthorized'], 401);
}
// 继续执行
return $next($request);
}
}
步骤 2:注册到路由
// route/app.php
Route::group('api', function () {
Route::get('user', 'User/index');
})->middleware(\app\middleware\Check::class);
在原生 PHP 中手动实现中间件
如果项目没有使用框架,或者想理解中间件的底层原理,可以手动实现一个简单的“洋葱模型”中间件。
核心概念:通过递归或数组遍历,让请求像“剥洋葱”一样依次经过每个中间件。
示例代码:
<?php
// 1. 定义中间件接口
interface MiddlewareInterface {
public function handle($request, Closure $next);
}
// 2. 定义具体的中间件类
class AuthMiddleware implements MiddlewareInterface {
public function handle($request, Closure $next) {
echo "[Auth] 正在验证...\n";
if (!isset($request['user'])) {
return "Unauthorized"; // 拦截
}
$response = $next($request); // 传递给下一个
echo "[Auth] 响应后处理\n";
return $response;
}
}
class LogMiddleware implements MiddlewareInterface {
public function handle($request, Closure $next) {
echo "[Log] 记录请求: " . json_encode($request) . "\n";
$start = microtime(true);
$response = $next($request);
$duration = round((microtime(true) - $start) * 1000, 2);
echo "[Log] 耗时: {$duration}ms\n";
return $response;
}
}
// 3. 中间件调度器
class MiddlewarePipeline {
private $middlewareList = [];
public function add(MiddlewareInterface $middleware) {
$this->middlewareList[] = $middleware;
}
public function run($request, Closure $finalHandler) {
// 使用 array_reduce 构建洋葱管道
$pipeline = array_reduce(
array_reverse($this->middlewareList),
function ($next, $middleware) {
return function ($request) use ($middleware, $next) {
return $middleware->handle($request, $next);
};
},
$finalHandler // 最内层的核心逻辑(控制器)
);
return $pipeline($request);
}
}
// 4. 使用示例
$request = ['user' => 'admin', 'action' => 'view'];
$pipeline = new MiddlewarePipeline();
$pipeline->add(new AuthMiddleware());
$pipeline->add(new LogMiddleware());
// 最终控制器处理
$finalController = function ($request) {
echo "[Controller] 执行业务逻辑...\n";
return "Hello, " . $request['user'];
};
$response = $pipeline->run($request, $finalController);
echo "\n最终响应: " . $response . "\n";
输出效果:
[Auth] 正在验证...
[Log] 记录请求: {"user":"admin","action":"view"}
[Controller] 执行业务逻辑...
[Log] 耗时: 0.00ms
[Auth] 响应后处理
最终响应: Hello, admin
这个例子展示了中间件如何“包裹”核心逻辑,按顺序执行预处理,然后逆序执行后处理。
典型应用场景
| 场景 | 说明 |
|---|---|
| 身份认证 | 检查用户是否登录,未登录则重定向 |
| 权限控制 | 检查用户角色是否允许访问某路由 |
| 日志记录 | 记录请求详情、执行耗时 |
| 跨域资源共享 (CORS) | 添加 Access-Control-Allow-Origin 头 |
| 请求频率限制 | 使用 Redis 等限制 IP 访问频率 |
| 输入清洗 / 验证 | 去除 HTML 标签或验证格式 |
| 缓存 | 检查是否有缓存,有则直接返回 |
需要注意的坑
- 中间件顺序很重要:先注册的中间件先执行预处理,后执行后处理(洋葱模型)。
- 阻塞与拦截:中间件中可以返回响应(如 401、重定向),从而阻止请求继续向下传递。
- 性能影响:过多中间件或中间件中执行慢操作(如数据库查询)会影响整体响应速度。
- 框架差异:不同框架对中间件的命名、注册方式、前置/后置钩子的实现细节不同,参考对应文档。
- 框架开发者:直接使用框架自带的中间件系统即可(Laravel
middleware、ThinkPHPmiddleware、Yii2filters)。 - 原生项目:可以手动实现一个简单的中间件管道(Pipeline),理解其洋葱模型原理。
- 核心思想:中间件 = 请求的前置处理 + 核心逻辑 + 响应的后置处理,通过管道串联起来。