路由级中间件一定先于控制器级中间件执行,顺序为全局→路由→控制器→方法级;注解中间件不生效主因是未返回$next、命名空间错误或作用于static方法。

ThinkPHP 路由中间件和控制器中间件谁先执行
路由级中间件一定先于控制器级中间件执行。这是 ThinkPHP 6+ 的硬性调度顺序,不是配置能改的——app/middleware.php 里注册的全局中间件、路由分组里用 middleware() 绑定的中间件、以及控制器类顶部注解 @middleware 声明的中间件,三者按「路由匹配前 → 路由匹配后(但控制器未实例化)→ 控制器方法调用前」逐层触发。
常见错误现象:AuthMiddleware 放在控制器注解里,结果请求连路由都没匹配上就 404 了,用户以为“没生效”,其实是根本没走到那一步;或者在路由中间件里修改了 $request,但控制器里却读不到,因为中间件返回了 Response 提前终止了流程。
- 路由级中间件在
Route::get('/user', 'User::index')->middleware(AuthCheck::class)这种写法中生效,它会在路由解析完成、参数注入前执行 - 控制器级中间件靠注解
@middleware('CheckRole')或控制器构造函数中调用$this->middleware(CheckRole::class),只对当前控制器所有方法有效,且必须等路由已确认命中该控制器才启动 - 若同一请求同时命中路由级和控制器级中间件,执行顺序固定为:全局中间件 → 路由中间件 → 控制器中间件 → 方法级中间件(如有)
如何让某个路由跳过全局中间件但保留路由级中间件
ThinkPHP 不支持“局部禁用全局中间件”,但可以绕过:把原本写在 app/middleware.php 的全局中间件移出来,改用路由分组 + 条件绑定的方式控制粒度。
使用场景:后台接口需要 TokenVerify 全局校验,但登录路由 /api/login 必须放行;又不想为一个接口单独建个分组。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 删掉
app/middleware.php中的TokenVerify::class,改用路由定义时显式添加:Route::group(['middleware' => ['TokenVerify']], function () { ... }) - 登录路由单独写在外面,不进这个分组,自然不走
TokenVerify - 注意:不能用
except或only参数控制全局中间件——ThinkPHP 的全局中间件没有这种过滤机制 - 性能影响:路由分组方式不会增加运行时开销,中间件仍是懒加载,只是注册时机从启动阶段推迟到路由解析阶段
控制器注解中间件不生效的三个典型原因
不是注解写错就是生命周期理解偏差。最常踩的坑是把中间件当成“装饰器”来用,忽略了 ThinkPHP 的中间件必须返回 Request 或 Response 才能继续流程。
- 注解写成
@middleware(CheckLogin),但CheckLogin类里handle()方法末尾忘了return $next($request),导致后续流程直接中断,页面空白或 500 - 控制器用了命名空间别名,比如
use app\middleware\CheckLogin;,但注解里写了全路径@middleware(\app\middleware\CheckLogin::class),类名解析失败,中间件被忽略 - 注解写在方法上(如
@middleware('LogAccess')),但该方法是 public static,而 ThinkPHP 的方法级中间件只支持实例方法,static 方法不触发中间件链
调试中间件执行顺序的最快办法
别翻源码,直接在每个中间件的 handle() 开头加一行日志输出,用 echo 或 trace() 打点,比看文档快得多。
示例:在 app/middleware/AuthCheck.php 的 handle() 里写 trace('AuthCheck: start', 'middleware');,再在控制器注解中间件里也打同类型日志,然后访问接口,去 runtime/log/ 下查 middleware.log 就一目了然。
- 不要依赖
dd()或dump(),它们会中断响应,看不到后续中间件是否执行 - 避免在中间件里做耗时操作(如查库、远程调用),否则会影响整个请求链路,尤其是路由中间件——它可能被大量未登录用户触发
- 如果发现某中间件完全没日志,先检查类名拼写、命名空间、是否被正确注册(路由分组里写错名字、注解漏了引号等)
中间件顺序本身不难理清,难的是每个环节都得“有返回”“不抛异常”“类能自动加载”。漏掉任意一个,整个链就断在那儿,还不好定位。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










