中间件是请求/响应的拦截与增强层,遵循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'])在路由匹配后、控制器前执行,适合EncryptCookies、StartSession - 路由级中间件(
Route::middleware(['auth', 'throttle:60,1']))最晚生效,但若把auth放在throttle后面,未登录用户也能触发频率限制,浪费资源 - 最关键陷阱:
VerifyCsrfToken必须在StartSession之后,否则 session 未启动,CSRF token 读不到,所有 POST 表单都会 419
调试时可用 php artisan route:list --middleware 查看每个路由绑定的中间件及其顺序,比猜快得多。











