ThinkPHP 6 路由分组嵌套时 middleware 不生效,主因是严格模式下快捷方法脱离分组上下文;需用 rule 链式调用并声明 Route $route 参数,子域名需显式启用 match_all 或闭包验证,miss 兜底不触发因分组匹配优先级高。
ThinkPHP 6
路由
分组嵌套时
不生效?
不是中间件写错了,是分组定义顺序和闭包嵌套层级导致的解析提前终止。TP6.1+ 默认启用「严格模式」,
内部若用
/
等快捷方法直接注册路由,会脱离分组上下文,
、
、
全部丢失。
正确做法是统一用
或链式调用:
分组闭包参数必须声明为
,否则无法链式调用
在分组外调用只影响该分组入口,内部路由仍需单独加或统一用
TP6.2 起支持
嵌套
,但中间件不会自动透传,需显式调用
升级 TP6.3 后
加载 PHP 文件报错
根本原因是自动加载机制变更:TP6.3 移除了对
文件内类名与文件路径强绑定的容错逻辑,现在要求
的路由数组中所有控制器类必须能被 Composer 自动加载器识别。
常见错误场景:
立即学习
“
PHP免费学习笔记(深入)
”;
路由文件里写了
,但
没在
的
或
中声明
用了相对命名空间如
,而实际类文件在
下
文件本身用了
,但没加
前缀导致路径解析失败
修复方式(三选一):
把控制器加进
的
并运行
改用完整 FQCN:
(注意双反斜杠)
在
文件顶部加
,并确保返回数组中的类名与命名空间一致
的
参数在子域名下失效?
是的,TP6 默认只对主域名应用
,子域名路由需显式启用正则匹配。原因在于
类默认跳过
解析,除非手动开启。
典型表现:
中的
校验完全不触发,
会匹配任意字符串。
解决办法只有两个:
改用
强制启用全量匹配(推荐)
弃用
,改用闭包验证:
注意:
会影响性能,尤其当子域名下路由数 > 50 时,建议搭配
使用。
为什么
在多级分组后总是 404,连
都不触发?
因为
是全局兜底,但它注册时机早于所有分组解析。一旦任何分组匹配成功(哪怕最终没找到具体路由),
就不会再执行。
真实场景:你写了
,但请求的是
—— 此时 TP 先匹配到
分组,再在该分组内查找
,查不到就直接抛
,根本不会走到全局
。
可行方案:
每个分组末尾手动加一条
作为该分组内兜底
在
中捕获
,再做自定义跳转
禁用异常中断,改用
+
做前置校验(仅适合管理后台)
最易忽略的一点:TP6.3 新增了
,但它只对当前作用域生效,不能替代
,且不支持中间件链。
middlewaregroupgetpostmiddlewareprefixnamespacerule
// ❌ 错误:看似在 group 里,实际已脱离上下文
Route::group('api', function () {
Route::get('user', 'UserController@index'); // middleware 不生效
})->middleware('check_token');
// ✅ 正确:全部走 rule 链式,确保继承分组配置
Route::group('api', function (Route $route) {
$route->rule('user', 'UserController@index', 'GET')
->middleware('check_token');
})->middleware('check_token');
Route $routemiddleware()append()Route::domain()group()->middleware(...)Route::import()Class not foundimportreturn['index' => 'appcontroller2UserController@index']UserControllercomposer.jsonautoload.classmappsr-4'controllerUserController'app/controller/v2/importuse__DIR__composer.json"psr-4": {"app\": "app/"}composer dump-autoload'appcontroller2UserController@index'importnamespace app
oute;Route::rule()patternpatternDomainRulepatternRoute::domain('admin.example.com')->rule('user/:id', 'Admin/User/index', ['id' => 'd+'])id:idRoute::domain(...)->option(['match_all' => true])pattern->filter(function ($request) { return ctype_digit($request->param('id')); })match_allcacheRoute::miss()Route::any()missmissRoute::group('v1', [...])->middleware('auth')/v1/unknownv1unknownRouteNotFoundExceptionmissRoute::any('', function () { ... })->ext('*')app/middleware/RouteCheck.phpthinkexceptionRouteNotFoundExceptionRoute::isAvailable()Url::build()Route::fallback()miss