中间件使用指南
中间件是一种在请求到达控制器之前或之后处理请求的机制。它可以用来:
- 验证用户身份
- 记录请求日志
- CSRF 防护
- 请求参数验证
- 响应处理
- 等等
MiddlewareBase(中间件基类)
这是一个抽象类,是所有具体中间件的父类
相当于一个模板或合同,规定了所有中间件必须遵循的结构
你需要继承它来创建自己的中间件
包含 handle() 抽象方法,你必须在子类中实现这个方法
使用方式:class 你的中间件 extends MiddlewareBase
Middleware(中间件管理器)
这是一个工具类,用来管理和执行中间件
提供了注册、排序和运行中间件的方法
你需要调用它的方法来使用中间件功能
包含 pipeline()、register() 等静态方法
使用方式:Middleware::pipeline([中间件列表])
通俗解释
想象一下工厂生产线:
MiddlewareBase 就像生产线上的工位设计图,规定了每个工位必须有什么功能
Middleware 是整个生产线的控制系统,负责按顺序启动每个工位,协调它们的工作
或者想象一下餐厅:
MiddlewareBase 就像厨师岗位说明书,规定了所有厨师必须会做什么
Middleware 是餐厅经理,负责安排厨师们按顺序工作,把食物从厨房送到客人手中
什么时候使用哪个?
当你创建自己的中间件时,使用 use startmvc\core\MiddlewareBase;
当你想运行中间件时,使用 use startmvc\core\Middleware;
简单来说:创建用 Base,运行用 Manager。
1. 创建中间件
首先,创建一个中间件类,该类必须继承 `startmvc\core\MiddlewareBase` 并实现 `handle` 方法:
namespace app\middleware;
use startmvc\core\MiddlewareBase;
class AuthMiddleware extends MiddlewareBase
{
/**
* 处理传入的请求
*
* @param object $request 请求对象
* @param \Closure $next 下一个要执行的中间件
* @return mixed 响应对象
*/
public function handle($request, \Closure $next)
{
// 在请求处理前执行的代码
if (!isset($_SESSION['user_id'])) {
// 用户未登录,重定向到登录页面
header('Location: /login');
exit;
}
// 调用下一个中间件
$response = $next($request);
// 在请求处理后执行的代码
// 例如:修改响应内容
return $response;
}
}
2. 注册中间件
2.1 全局中间件
全局中间件会应用于所有请求。在应用启动时(例如在 `config/app.php` 或启动文件中)注册:
// 在 config/app.php 或启动文件中
use startmvc\core\Middleware;
// 注册全局中间件
Middleware::register(\app\middleware\LogMiddleware::class);
2.2 路由中间件
路由中间件只应用于特定路由:
// 在 routes.php 或其他路由配置文件中
use startmvc\core\Router;
// 应用中间件到单个路由
Router::get('/admin/dashboard', 'AdminController@dashboard', [
\app\middleware\AuthMiddleware::class
]);
// 应用中间件到路由组
Router::group(['middleware' => [\app\middleware\AuthMiddleware::class]], function() {
Router::get('/admin/users', 'AdminController@users');
Router::get('/admin/settings', 'AdminController@settings');
});
2.3 给中间件注册别名
为了使用更简洁的名称,可以为中间件注册别名:
use startmvc\core\Middleware;
// 注册中间件别名
Middleware::alias('auth', \app\middleware\AuthMiddleware::class);
Middleware::alias('log', \app\middleware\LogMiddleware::class);
// 然后可以使用别名
Router::get('/admin/dashboard', 'AdminController@dashboard', ['auth']);
3. 常用中间件示例
3.1 日志中间件
//app/middleware/LogMiddleware.php
namespace app\middleware;
use startmvc\core\MiddlewareBase;
use startmvc\core\Logger;
class LogMiddleware extends MiddlewareBase
{
public function handle($request, \Closure $next)
{
$startTime = microtime(true);
// 记录请求信息
Logger::info("Request: {$_SERVER['REQUEST_METHOD']} {$_SERVER['REQUEST_URI']}");
// 调用下一个中间件
$response = $next($request);
// 计算执行时间
$executionTime = microtime(true) - $startTime;
Logger::info("Response time: " . round($executionTime * 1000, 2) . "ms");
return $response;
}
}
3.2 CORS 中间件
//app/middleware/CorsMiddleware.php
namespace app\middleware;
use startmvc\core\MiddlewareBase;
class CorsMiddleware extends MiddlewareBase
{
public function handle($request, \Closure $next)
{
// 设置 CORS 头
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
// 处理预检请求
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
exit(0);
}
return $next($request);
}
}
3.3 CSRF 保护中间件
//app/middleware/CsrfMiddleware.php
namespace app\middleware;
use startmvc\core\MiddlewareBase;
use startmvc\core\Csrf;
class CsrfMiddleware extends MiddlewareBase
{
public function handle($request, \Closure $next)
{
// 跳过 GET 请求
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
return $next($request);
}
// 验证 CSRF Token
if (!Csrf::verify()) {
// CSRF 验证失败
throw new \Exception('CSRF token mismatch', 403);
}
return $next($request);
}
}
4. 在控制器中使用中间件
如果您想在控制器构造函数中应用中间件,可以这样做:
//app/controller/home/AdminController.php
namespace app\controllers;
use startmvc\core\Controller;
use startmvc\core\Middleware;
class AdminController extends Controller
{
public function __construct()
{
parent::__construct();
// 创建请求对象
$request = new \startmvc\core\Request();
// 应用中间件
Middleware::pipeline([\app\middleware\AuthMiddleware::class], $request, function($request) {
// 中间件通过后执行
return true;
});
}
public function dashboard()
{
// 控制器方法
}
}
5. 中间件执行流程
中间件的执行是洋葱模型,即:
1. 按照注册顺序执行每个中间件的前置操作
2. 到达控制器方法
3. 按照相反顺序执行每个中间件的后置操作
示意图:
中间件1(前置) → 中间件2(前置) → 控制器 → 中间件2(后置) → 中间件1(后置)
6. 传递数据给下一个中间件
可以在 `$request` 对象上附加数据,传递给下一个中间件或控制器:
public function handle($request, \Closure $next)
{
// 添加数据到请求对象
$request->user = User::find($_SESSION['user_id']);
return $next($request);
}
然后在控制器中可以使用这些数据:
public function dashboard($request)
{
$user = $request->user;
// ...
}