最常见原因是中间件名未在app/middleware.php中注册或拼写错误;其次路由未链式调用->middleware(),如Route::get('admin','Admin/index')->middleware('auth');分组路由中需将->middleware()置于Route::group()后、闭包前。

为什么 ->middleware() 写了却不触发
最常见原因是中间件名没注册或拼错,ThinkPHP 对字符串形式的中间件名(如 'auth')不做自动解析,必须在 app/middleware.php 中显式映射到类。比如写了 ->middleware('check_auth'),但配置里是 'checkAuth' 或压根没定义,就会静默跳过。
另一个高频坑:路由定义没链式调用 ->middleware()。只写 Route::get('admin', 'Admin/index') 是无效的,必须显式加链:Route::get('admin', 'Admin/index')->middleware('auth')。框架不会“扫描”路由自动挂中间件。
- 闭包路由、资源路由(
Route::resource())同样需要手动绑定,否则不进中间件 - 分组路由中,
->middleware()必须写在Route::group()之后、闭包之前,否则不生效 - 别名注册位置必须是
app/middleware.php的全局数组,不是 config 文件或其他地方
->middleware() 和 ->appendMiddleware() 执行顺序差异
ThinkPHP 默认把 ->middleware() 插入到中间件链最前面(洋葱模型最外层),也就是比所有全局中间件还早执行;而 ->appendMiddleware() 才是追加到末尾,紧挨着控制器逻辑前运行。
比如你有全局中间件 [Auth::class, Logger::class],又对某个路由调用 ->middleware(RateLimit::class),真实执行顺序是:RateLimit → Auth → Logger。如果想让它最后验权限(比如等日志打完再限流),就得改用 ->appendMiddleware(RateLimit::class)。
立即学习“PHP免费学习笔记(深入)”;
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 多个
->middleware()链式调用时,越靠前的越先执行(请求阶段) -
->middleware(['a', 'b'])数组传入,等价于连续两次->middleware('a')->middleware('b') - 中断必须返回
think\Response实例,return json([...])可以,return;或echo + exit不行
分组路由中 prefix 和 middleware 的绑定时机
必须把 ->prefix() 和 ->middleware() 链在 Route::group() 后、闭包前完成,且子路由必须在闭包内用 Route::get() 等静态方法注册——不能在闭包外另起一行写 Route::get(),否则脱离分组上下文,前缀和中间件全失效。
典型错误写法:Route::group('api', function () { Route::get('user', ...); })->prefix('v1')->middleware('cors');。这里 ->prefix() 和 ->middleware() 只作用于 group 实例本身,而闭包里的 Route::get() 是全新注册的独立路由,不继承任何配置。
- 正确顺序:
Route::group('api')->prefix('v1')->middleware('cors')->route(function () { Route::get('user', ...); }); -
->prefix()会自动规整斜杠,->prefix('/api')和->prefix('api')效果一致 - 嵌套分组不推荐,
->prefix()虽然支持叠加,但调试时X-Middleware-Stack响应头很难直观对应层级
调试中间件是否真正执行
开 middleware_trace 是最直接的办法:在 config/app.php 中设 'middleware_trace' => true,响应头会出现 X-Middleware-Stack 字段,逗号分隔列出本次请求**实际进入执行流程**的中间件类名,按执行顺序排列。
如果某个中间件没出现在这个字段里,大概率不是顺序配错了,而是被前面中间件用 return $next($request) 正常放行了,或者更可能是被条件逻辑提前 return 出去(比如未登录直接 return json(...)),导致后续中间件根本没机会加载。
- 该字段只显示“进了洋葱圈”的中间件,跳过被短路的项
- 闭包中间件、匿名函数中间件不会显示完整类名,只显示
Closure,需结合日志定位 - 中间件里想读路由参数,必须用
$request->rule()->getoption()或$request->rule()->getaction(),不能依赖全局变量或构造注入


















