ThinkPHP中间件与管道模式详解
中间件概念
中间件是ThinkPHP中一个重要的机制,它在请求到达控制器之前或响应返回客户端之前执行一系列的处理操作,中间件采用管道模式(Pipeline)设计,类似于洋葱模型。

管道模式原理
// 管道模式示意图
请求(Request) → 中间件1 → 中间件2 → 控制器 → 中间件2 → 中间件1 → 响应(Response)
↓ ↓ ↑ ↑
前置操作 前置操作 后置操作 后置操作
中间件的创建与注册
创建中间件
<?php
// app/middleware/AuthMiddleware.php
namespace app\middleware;
use Closure;
use think\Request;
use think\Response;
class AuthMiddleware
{
/**
* 中间件入口方法
*/
public function handle($request, Closure $next)
{
// 前置操作:请求处理前
if (!$this->checkAuth($request)) {
return json(['code' => 401, 'msg' => '未登录'], 401);
}
// 传递给下一个中间件/控制器
$response = $next($request);
// 后置操作:响应处理后
$response->header('X-Auth-Middleware', 'processed');
return $response;
}
private function checkAuth($request)
{
// 认证逻辑
return true;
}
}
注册中间件
// config/middleware.php
return [
// 全局中间件
'global' => [
app\middleware\AuthMiddleware::class,
app\middleware\CorsMiddleware::class,
],
// 分组中间件
'groups' => [
'admin' => [
app\middleware\AdminCheckMiddleware::class,
app\middleware\PermissionMiddleware::class,
],
'api' => [
app\middleware\ApiRateLimitMiddleware::class,
app\middleware\ApiResponseMiddleware::class,
],
],
// 路由中间件
'route' => [
'auth' => app\middleware\AuthMiddleware::class,
'log' => app\middleware\LogMiddleware::class,
'cors' => app\middleware\CorsMiddleware::class,
],
// 中间件别名
'alias' => [
'csrf' => app\middleware\CsrfMiddleware::class,
'admin' => app\middleware\AdminCheckMiddleware::class,
],
];
中间件应用场景示例
CORS 跨域中间件
<?php
// app/middleware/CorsMiddleware.php
namespace app\middleware;
use Closure;
use think\Request;
class CorsMiddleware
{
public function handle($request, Closure $next)
{
$origin = $request->header('Origin', '*');
// 处理预检请求
if ($request->isOptions()) {
return response()
->code(204)
->header([
'Access-Control-Allow-Origin' => $origin,
'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers' => 'Content-Type, Authorization, X-Requested-With',
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Max-Age' => '86400',
]);
}
// 正常请求处理
$response = $next($request);
// 设置响应头
$response->header([
'Access-Control-Allow-Origin' => $origin,
'Access-Control-Allow-Credentials' => 'true',
]);
return $response;
}
}
请求日志中间件
<?php
// app/middleware/LogMiddleware.php
namespace app\middleware;
use Closure;
use think\Request;
use think\facade\Log;
class LogMiddleware
{
public function handle($request, Closure $next)
{
$startTime = microtime(true);
// 记录开始时间
Log::info('Request Start', [
'url' => $request->url(),
'method' => $request->method(),
'ip' => $request->ip(),
'params' => $request->param(),
]);
$response = $next($request);
// 计算执行时间
$execTime = microtime(true) - $startTime;
// 记录结束信息
Log::info('Request End', [
'status' => $response->getCode(),
'time' => round($execTime, 4),
'response' => mb_substr($response->getContent(), 0, 1000),
]);
return $response;
}
}
权限验证中间件
<?php
// app/middleware/PermissionMiddleware.php
namespace app\middleware;
use Closure;
use think\Request;
use think\facade\Cache;
use think\facade\Session;
class PermissionMiddleware
{
public function handle($request, Closure $next, $permission = null)
{
// 获取当前用户
$user = Session::get('user');
if (!$user) {
return json(['code' => 401, 'msg' => '请先登录']);
}
// 检查权限
if ($permission && !$this->checkPermission($user['id'], $permission)) {
return json(['code' => 403, 'msg' => '无权限访问']);
}
// 将用户信息注入到Request中
$request->user = $user;
return $next($request);
}
private function checkPermission($userId, $permission)
{
$permissions = Cache::get('user_permissions_' . $userId);
if (!$permissions) {
// 从数据库加载权限
$permissions = $this->loadPermissions($userId);
Cache::set('user_permissions_' . $userId, $permissions, 3600);
}
return in_array($permission, $permissions);
}
private function loadPermissions($userId)
{
// 数据库查询逻辑
return ['admin.list', 'admin.edit', 'article.create'];
}
}
中间件的使用方式
路由中使用
// route/app.php
use think\facade\Route;
// 单个中间件
Route::get('user/:id', 'User/read')->middleware('auth');
// 多个中间件
Route::post('article', 'Article/save')->middleware([
'auth',
'permission:article.create',
]);
// 分组使用
Route::group('admin', function () {
Route::get('list', 'Admin/list');
Route::post('save', 'Admin/save');
})->middleware([
'auth',
'admin',
'permission:admin.manage'
]);
控制器中使用
<?php
namespace app\controller;
use think\Request;
class User extends Base
{
// 定义控制器中间件
protected $middleware = [
'auth' => [
'except' => ['login', 'register'] // 排除登录和注册方法
],
'log',
'permission:user.manage' => [
'only' => ['delete', 'edit'] // 仅对delete和edit生效
],
];
public function list()
{
// ...
}
}
管道模式的高级特性
中间件参数传递
<?php
namespace app\middleware;
use Closure;
use think\Request;
class AdvancedMiddleware
{
public function handle($request, Closure $next, ...$params)
{
// 使用参数
if (in_array('check-ip', $params)) {
// IP检查逻辑
}
if (in_array('check-agent', $params)) {
// User-Agent检查逻辑
}
return $next($request);
}
}
// 使用:'middleware' => 'advanced:check-ip,check-agent'
终止中间件(响应后处理)
<?php
namespace app\middleware;
use think\Response;
class TerminateMiddleware
{
/**
* 响应结束后执行
*/
public function end(Response $response)
{
// 记录日志、清理临时文件、发送通知等
\think\facade\Log::info('Response ended', [
'status' => $response->getCode(),
'time' => date('Y-m-d H:i:s')
]);
}
}
性能优化建议
<?php
// 1. 使用异步中间件
public function handle($request, Closure $next)
{
// 仅定义但不执行,返回闭包
return $next($request)->then(function ($response) {
// 异步处理
return $response;
});
}
// 2. 条件性中间件
public function handle($request, Closure $next)
{
// 通过配置动态启用
if (config('app.debug')) {
return $next($request);
}
// 生产环境的额外处理
return $next($request);
}
最佳实践
- 中间件职责单一:每个中间件只做一件事
- 合理排序:认证中间件应该在最前面,日志最后
- 避免过度嵌套:合理组织中间件,避免性能损耗
- 异常处理:在中间件中做好异常捕获
- 缓存利用:频繁的数据查询可通过中间件缓存
通过合理使用ThinkPHP的中间件和管道模式,可以实现灵活的请求处理流程,提高代码的可维护性和可扩展性。