ThinkPHP路由中间件必须在app/middleware.php中注册为全局中间件才能拦截所有请求,但易误拦静态资源;推荐使用route/middleware.php分组中间件精准控制,并确保handle方法显式return $next($request)。

ThinkPHP 路由中间件怎么注册才能拦截所有请求
必须在 app/middleware.php 中注册为全局中间件,否则只对特定路由生效。但要注意:全局中间件会作用于所有 HTTP 请求(包括静态资源、API、后台接口),容易误拦 public/ 下的 JS/CSS 或登录接口,导致白屏或 403。
实操建议:
- 优先用
app/middleware.php的数组方式注册,例如:['app\middleware\AuthCheck'];不要依赖命令行php think middleware:install,它生成的是类名字符串,不带命名空间易出错 - 若只需拦截控制器路由(排除静态资源),改用
route/middleware.php中的['http']分组中间件,更精准 - 中间件类必须实现
handle方法,且末尾必须显式return $next($request),漏写会导致请求中断无响应
权限判断逻辑该放中间件里还是控制器基类里
放中间件里。控制器基类(如 BaseController)的 initialize() 是运行时才触发,无法阻止路由匹配后、控制器实例化前的非法访问;而中间件在路由解析后、调度前执行,能真正“拦截”。
常见错误现象:
立即学习“PHP免费学习笔记(深入)”;
- 用户未登录却能访问
/admin/user/list页面——其实是路由已匹配成功,initialize()才抛异常,页面 HTML 已部分渲染 - 中间件中调用
$this->redirect()报错——因为中间件无视图上下文,应改用response()->redirect('/login')或直接返回json(['code'=>401]) - 权限校验依赖 Session,但 CLI 命令或队列任务中 Session 不可用,需加
if (app()->isCli()) return $next($request);防止崩溃
如何让中间件跳过登录页、验证码、API 公共接口
不能靠中间件内部硬编码路径判断,维护成本高且易漏。推荐在路由定义时显式排除:
在 route/app.php 中使用 ->except() 或分组隔离:
// 方式一:给不需要鉴权的路由加标签
Route::get('login', 'Login/index')->name('login');
Route::get('captcha', 'Common/captcha');
// 方式二:用中间件分组(推荐)
Route::group('api', function () {
Route::post('login', 'Api/Login/login');
Route::post('sms/send', 'Api/Sms/send');
})->middleware('throttle:10,1'); // 只限流,不鉴权
Route::group('admin', function () {
Route::get('index', 'Admin/index');
Route::get('user/list', 'Admin/userList');
})->middleware('auth'); // 这里才加权限中间件
注意:->middleware('auth') 必须写在分组闭包之后,写在内部无效;且中间件名要和 app/middleware.php 中注册的键名一致(默认是类名小写)。
为什么 AuthCheck 中间件里获取不到当前路由名
因为 $request->url() 返回的是原始 URL,不是路由变量;$request->rule() 在中间件中可能为空——此时路由尚未完全解析完成。
正确做法是用 $request->action(true)(TP6.1+)或 $request->controller() . '/' . $request->action(),但前提是路由已绑定到控制器方法。更稳妥的方式是:在中间件中读取 $request->routeInfo()['rule'] ?? '',它是框架解析后的路由规则字符串(如 'admin/user/:id' )。
性能提示:避免在中间件中频繁查数据库做权限比对。应提前将用户角色对应的可访问路由规则缓存为数组,用 in_array($rule, $allowRules) 判断,比每次查表快一个数量级。
容易被忽略的一点:TP6 默认开启路由缓存,修改 route/app.php 后必须运行 php think route:clear,否则新添加的 ->middleware() 不生效。


















