ThinkPHP 6.0 废弃 app/middleware.php 全局注册,强制显式绑定路由或钩子;handle() 方法需严格类型约束与 Response 返回;多应用下中间件不自动继承,须单独配置或映射。

中间件注册方式变了,app/middleware.php 文件直接废弃
ThinkPHP 6.0 彻底取消了 TP5.1 中通过 app/middleware.php 返回数组注册全局中间件的方式。现在所有中间件必须显式绑定到路由或应用生命周期钩子上,没有“默认全局生效”这回事。
常见错误现象:Class not found 或中间件完全不执行——往往是因为你还留着 app/middleware.php,却没在路由里调用它;或者类路径/命名空间没对齐 PSR-4(比如写成 app\middleware\CorsMiddleware,但文件实际在 app/middleware/cors.php)。
- 注册全局中间件:在
app/provider.php中通过think\App的bind或beforeStart钩子注入,但更推荐按需绑定 - 路由级绑定:用
->middleware()链式调用,支持类名、闭包、带参数的数组形式(如[\app\middleware\AuthMiddleware::class, 'admin']) - 控制器级绑定:在控制器构造函数中调用
$this->middleware(),类似 Laravel 风格
handle() 方法签名强制类型约束,不兼容 TP5.1 的松散写法
TP6 的中间件 handle() 方法必须严格声明参数类型和返回类型:public function handle(Request $request, Closure $next): Response。TP5.1 允许无类型、混合类型甚至只写 $request, $next,升级后不改会直接报致命错误。
使用场景:当你把 TP5.1 的中间件原样复制进 TP6,运行就卡在 TypeError: Argument 1 passed to ... must be an instance of think\Request。
立即学习“PHP免费学习笔记(深入)”;
- TP5.1 的
think\Request在 TP6 中已移入think\facade\Request或直接用依赖注入的think\Request实例(注意不是 facade) - 返回值必须是
think\Response类型,不能 return 字符串、数组或空 —— 否则管道中断,后续中间件和控制器都不执行 - 如果中间件要做鉴权拦截,必须显式
return response()->fail('未登录')->code(401),不能再靠exit或halt()
权限控制逻辑要从“前置判断”转向“管道流控”,否则容易漏掉跨域/日志等环节
TP5.1 的中间件是线性堆叠,顺序执行完再进控制器;TP6 是基于 PSR-15 的标准管道(pipeline),每个中间件决定是否把请求“传下去”。这意味着:如果你在权限中间件里做了拦截但忘了 return 响应,而是直接 echo 或 die,后续中间件(比如 CORS、日志记录)就彻底失效。
性能影响:TP6 管道模式天然支持短路,合理设计可减少不必要的中间件初始化(比如未登录用户根本不会触发数据库查询中间件);但若误用 $next($request) 后还继续写逻辑,反而增加开销。
- 典型错误:在
AuthMiddleware中检查 token 失败后写了echo json_encode([...]); die;→ 跨域头丢失、日志不记录、监控无上报 - 正确做法:统一用
return response()->json([...])->code(403),确保响应对象经过完整管道 - 调试技巧:加一个最外层日志中间件,打印
$request->url()和$response->getCode(),能一眼看出哪个环节截断了流程
多应用下中间件作用域变窄,think-multi-app 不自动继承主应用中间件
TP6 默认单应用,启用 think-multi-app 后,每个子应用(如 app/admin)的中间件必须单独配置。主应用 app/middleware/ 下的类不会自动加载到 admin 应用的路由管道里——这点和 TP5.1 的模块共享机制完全不同。
容易踩的坑:你在 app/middleware/AuthMiddleware.php 写了后台权限逻辑,然后在 route/admin.php 里绑定了它,结果跑起来提示 Class app\middleware\AuthMiddleware does not exist。
- 原因:TP6 多应用模式下,子应用的命名空间默认是
app\admin,自动加载器只扫app/admin/middleware/,不扫根app/middleware/ - 解决方法一:把权限中间件复制一份到
app/admin/middleware/,命名空间改成app\admin\middleware - 解决方法二:在
app/admin/provider.php中手动添加 PSR-4 映射:$this->app->bind('app\middleware', APP_PATH . 'middleware/') - 不建议共用:权限策略往往因前台/后台差异很大,硬共用反而增加维护成本
最麻烦的其实是中间件之间的隐式依赖——比如你写了日志中间件依赖请求 ID,而请求 ID 又由另一个中间件注入,TP6 管道里顺序错了就全崩。这类问题不会报错,只会让日志字段为空或者监控数据断层,得靠请求链路追踪才能发现。


















