本文目录导读:

在 PHP 项目框架中,中间件(Middleware)是一种非常强大的机制,用于在请求到达控制器之前或响应返回给客户端之前执行特定的逻辑。
下面我将以当前最主流的 PHP 框架 Laravel 和 ThinkPHP 为例,详细讲解中间件的开发和使用方法,这两个框架的中间件概念类似,但实现细节不同。
核心概念
中间件就像一个“过滤层”或“处理管道”,请求必须通过这些管道才能到达最终的处理程序(控制器)。
常见用途:
- 身份认证(Auth)
- 日志记录
- 跨域请求(CORS)
- CSRF 保护
- 请求频率限制
- 请求数据过滤
Laravel 中间件实战 (最常用)
Laravel 的中间件是所有 PHP 框架中最成熟的实现之一。
创建中间件
使用 Artisan 命令创建:
php artisan make:middleware CheckAge
这会在 app/Http/Middleware/CheckAge.php 生成文件。
编写中间件逻辑
核心逻辑写在 handle 方法中。
示例:年龄验证中间件
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class CheckAge
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
// 1. 前置逻辑:请求到达控制器之前执行的代码
if ($request->age < 18) {
// 如果年龄小于18,直接返回响应,终止请求继续往下走
return redirect('home');
}
// 2. 传递请求到下一个中间件或控制器
$response = $next($request);
// 3. 后置逻辑:控制器处理完后的响应处理
// 给响应头部添加自定义信息
$response->headers->set('X-Middleware-Info', 'Age checked');
return $response;
}
}
关键点解析:
$next($request):将请求传递给管道中的下一个处理器,如果不调用,请求链就会终止。- 在
$next之前的代码是前置中间件(请求来时执行)。 - 在
$next之后的代码是后置中间件(响应返回时执行)。
注册中间件
需要告诉 Laravel 这个中间件存在,打开 app/Http/Kernel.php。
有三种注册方式:
-
全局中间件:所有 HTTP 请求都会经过。
// 在 $middleware 属性中添加 protected $middleware = [ // \App\Http\Middleware\TrustProxies::class, \App\Http\Middleware\CheckAge::class, // 添加这行 ]; -
路由中间件:只有在特定路由或路由组中使用时才会执行(推荐,更灵活)。
// 在 $routeMiddleware 属性中添加 protected $routeMiddleware = [ // 'auth' => \App\Http\Middleware\Authenticate::class, 'check.age' => \App\Http\Middleware\CheckAge::class, // 给中间件起个名字 'check.age' ];
使用中间件
在 routes/web.php 或 routes/api.php 中应用。
use Illuminate\Support\Facades\Route;
// 方式一:单个路由使用
Route::get('/admin/profile', function () {
// ...
})->middleware('check.age');
// 方式二:路由组使用(最常见)
Route::middleware(['check.age'])->group(function () {
Route::get('/admin/dashboard', [AdminController::class, 'dashboard']);
Route::get('/admin/settings', [AdminController::class, 'settings']);
});
ThinkPHP 6+ 中间件实战
ThinkPHP 6 引入了与 Laravel 非常相似的中间件机制。
创建中间件
使用命令创建(需要安装 topthink/think-middleware)或手动创建:
php think make:middleware CheckAge
文件生成在 app/middleware/CheckAge.php。
编写中间件逻辑
ThinkPHP 的核心方法是 handle,签名略有不同。
<?php
declare (strict_types=1);
namespace app\middleware;
use Closure;
class CheckAge
{
/**
* 处理请求
*
* @param \think\Request $request
* @param \Closure $next
* @return Response
*/
public function handle($request, \Closure $next)
{
// 前置逻辑
if ($request->param('age') < 18) {
// 终止请求,返回错误
return redirect('/home');
}
// 传递请求
$response = $next($request);
// 后置逻辑
$response->header('X-Middleware-Info', 'Age checked');
return $response;
}
}
注册中间件
打开 app/middleware.php 配置文件(如果没有则创建)。
// 全局注册
return [
// 全局中间件
app\middleware\CheckAge::class,
// 或者为特定模块注册
];
分组注册(推荐): 在 app/provider.php 或 route/app.php 中。
// 在 route.php 中
use think\facade\Route;
Route::group('admin', function () {
Route::rule('dashboard', 'admin/index/dashboard');
Route::rule('settings', 'admin/index/settings');
})->middleware(\app\middleware\CheckAge::class);
使用
ThinkPHP 6 支持在控制器构造函数中定义中间件。
// 在控制器中
protected $middleware = [
\app\middleware\CheckAge::class => ['except' => ['login', 'register']],
];
高级技巧与多参数中间件
带参数的中间件 (Laravel 示例)
如果你想让中间件更灵活,比如要求年龄大于某个值。
// app/Http/Middleware/CheckAge.php
public function handle(Request $request, Closure $next, $minAge)
{
if ($request->age < $minAge) {
return redirect('home');
}
return $next($request);
}
使用:
Route::get('/admin/profile', function () {
// ...
})->middleware('check.age:18'); // 冒号后传参
终止中间件 (Terminable Middleware)
有时需要在 HTTP 响应发送之后执行一些操作(例如记录日志或缓存),Laravel 支持 terminate 方法。
public function terminate($request, $response)
{
// 响应已发送,执行后处理
Log::info('Request processed');
}
中间件的执行顺序
- 全局中间件 最先执行。
- 路由中间件 按注册顺序执行。
- 在同一个路由组中,中间件的顺序很重要,前面的先执行(前置)或后执行(后置)。
最佳实践建议
- 保持单一职责:一个中间件只做一件事(如:CheckAge 只检查年龄,Auth 只做认证)。
- 优先使用路由中间件:全局中间件会使所有请求都变慢,只在你需要的地方使用中间件。
- 注意性能:不要在中间件中执行耗时的数据库查询或文件 IO。
- 异常处理:如果中间件检测到问题,直接返回
response()或抛出HttpException而不要继续处理。 - 测试中间件:中间件是逻辑集中的地方,务必编写单元测试。
无论是 Laravel 还是 ThinkPHP,中间件的核心思想都是“请求处理管道”。
- 创建 -> 编写
handle方法。 - 注册 -> 在 Kernel 或配置文件中注册。
- 使用 -> 在路由或控制器中指定。
掌握了中间件,你就掌握了现代 PHP 框架的核心设计模式之一,能够极大地提高代码的复用性和可维护性。