17370845950

PHP架构里中间件是干嘛的_常见用法举例【解答】
中间件是请求/响应的拦截与增强层,遵循PSR-15标准,通过process()或handle()方法在路由前/响应后执行横切逻辑;Laravel中需注意顺序、OPTIONS预检处理及CSRF与Session依赖关系。

中间件本质是请求/响应的拦截与增强层

PHP 中间件不是框架自带的“功能模块”,而是一种设计模式——它在 HTTP 请求 到达路由处理逻辑之前,或在 响应 发送给客户端之前,插入可复用的处理逻辑。它不替代控制器,也不直接生成页面,而是负责横切关注点(如鉴权、日志、CORS、请求解析等)。

主流 PHP 框架(Laravel、Slim、Zend Expressive、Mezzio)都基于 PSR-15 标准实现中间件接口:MiddlewareInterface::process() 接收 $request$handler,必须调用 $handler->handle($request) 向下传递,否则请求会中断。

Laravel 中间件最常见三类写法

实际项目中 80% 的中间件需求集中在以下三类,写法差异直接影响可维护性:

  • 闭包式中间件(适合调试或临时逻辑): 直接在 app/Http/Kernel.php$middleware 数组里写 function ($request, $next) { ... return $next($request); } —— 但无法被测试、不能复用、IDE 无提示,上线前务必移出
  • 类形式中间件(推荐): 执行 php artisan make:middleware CheckAge 生成标准类,核心是 handle() 方法;注意:$next($request) 必须被调用且只能调用一次,漏掉就卡死,多调用会重复执行后续中间件
  • 前置/后置分离逻辑(易被忽略): 若需在响应发出后做清理(如记录耗时、关闭连接),不能只靠 return $next($request)->withHeader(...);得先拿到响应,再操作:
    public function handle($request, Closure $next)
    {
        $startTime = microtime(true);
        $response = $next($request);
        $elapsed = microtime(true) - $startTime;
        \Log::info('Request time', ['ms' => round($elapsed * 1000)]);
        return $response;
    }

跨域(CORS)中间件为什么常失效

很多开发者照抄示例加了 Access-Control-Allow-Origin 头,但浏览器仍报错,根本原因是没覆盖预检请求(OPTIONS)路径,或未透传凭证相关头。正确做法:

立即学习“PHP免费学习笔记(深入)”;

  • 中间件必须对 OPTIONS 请求直接返回 200 响应,不调用 $next()
  • 若前端带 credentials: true,后端必须设 Access-Control-Allow-Credentials: true,且 Access-Control-Allow-Origin 不能为 *,得写具体域名(如 https://example.com
  • Laravel 自带的 Illuminate\Http\Middleware\HandleCors 默认不启用,需在 app/Http/Kernel.php$middleware 里显式添加,或在 cors.php 配置中打开 'supports_credentials' => true

中间件顺序错误会导致鉴权绕过

中间件执行顺序严格依赖注册位置。例如 Laravel 中:

  • 全局中间件($middleware)最先执行,适合日志、TrustedProxy
  • 分组中间件($middlewareGroups['web'])在路由匹配后、控制器前执行,适合 EncryptCookiesStartSession
  • 路由级中间件(Route::middleware(['auth', 'throttle:60,1']))最晚生效,但若把 auth 放在 throttle 后面,未登录用户也能触发频率限制,浪费资源
  • 最关键陷阱:VerifyCsrfToken 必须在 StartSession 之后,否则 session 未启动,CSRF token 读不到,所有 POST 表单都会 419

调试时可用 php artisan route:list --middleware 查看每个路由绑定的中间件及其顺序,比猜快得多。