StartMVC开发手册

可以快速上手的开发文档

手册目录

中间件

中间件使用指南

中间件是一种在请求到达控制器之前或之后处理请求的机制。它可以用来:

- 验证用户身份

- 记录请求日志

- 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;
    // ...
}