前置中间件在控制器执行前运行,后置中间件在控制器执行完、响应生成后运行;区别仅在于handle()中$next($request)调用位置:前置将其置于逻辑末尾并return,后置先调用再处理$response。

前置中间件在控制器执行前运行,后置中间件在控制器执行完、响应生成后才运行——本质区别就在这一个 $next($request) 的位置。
执行时机决定一切
ThinkPHP 不靠注册方式或类名区分前置/后置,只看 handle() 方法中 $next($request) 调用的位置:
- 如果所有逻辑写在 return $next($request); 之前,就是前置中间件:请求被拦截、校验、改参,控制器还没开始跑
- 如果先写 $response = $next($request);,再处理 $response,就是后置中间件:控制器已执行完毕,甚至可能已写入数据库、触发事件
能访问的上下文完全不同
前置中间件里,路由尚未完成解析:
- request()->controller() 和 request()->action() 返回空或默认值(如 index/index)
- 无法基于具体控制器做差异化判断,适合通用检查(如登录态、IP限流、Header校验)
后置中间件里,整个请求生命周期已走到尾声:
立即学习“PHP免费学习笔记(深入)”;
- 可安全调用 request()->controller()、request()->action()、$response->getCode() 等
- 适合按模块记录日志、统一包装 JSON 响应结构、注入 CORS 头、统计耗时
错误写法会直接破坏流程
看似微小的顺序错位,会导致语义完全颠倒:
- 前置中间件里漏掉 return,比如只写
$next($request);:PHP 返回 null,框架无响应,浏览器卡死或报 500 - 前置中间件里把重定向写在 $next() 后面:控制器先执行,用户看到的是业务输出+跳转混乱,甚至产生脏数据
- 后置中间件没接住异常:$next($request) 可能抛出 Exception 而非 Response,需用 try/catch 包裹,否则中断后续处理
典型使用场景对比
选前置还是后置,取决于你要干预的阶段:
- 必须用前置:未登录跳登录页、Token 过期拦截、非法参数直接拒绝、敏感操作二次验证
-
必须用后置:记录完整请求路径与耗时、给所有 API 响应加
X-Response-Time头、统一错误格式包装、响应体压缩 - 不能混用:权限校验放后置,意味着控制器代码已执行——哪怕最后跳转,DB 写入、消息推送、计费逻辑都已完成



















