thinkphp6中间件执行顺序由注册数组索引决定,config/middleware.php从左到右即请求进入顺序;路由级middleware()默认前置插入,appendmiddleware()才追加末尾;多应用下需各app/{name}/middleware.php单独配置。

ThinkPHP6 中间件执行顺序错乱,本质不是“优先级”可动态配置的问题,而是注册顺序与执行时机被误解导致的。它没有类似 Laravel 的 priority 数组或权重机制,顺序即逻辑,注册即生效。
全局中间件顺序由 config/middleware.php 数组索引决定
该文件是 ThinkPHP6 的全局中间件注册入口(注意:app/middleware.php 在 TP6+ 已废弃,仅多应用模式下对应应用目录内使用)。
数组从左到右,就是请求进入时的执行顺序:
- 第一个元素最先执行(最外层洋葱皮)
- 最后一个元素最后执行(最内层,紧邻控制器)
// config/middleware.php
return [
\think\middleware\ForceHttps::class, // 必须最前:不依赖 request 解析
\think\middleware\ValidatePostSize::class, // 防大文件绕过后续校验
\think\middleware\ParseJsonBody::class, // 确保 $request->post() 可用
\app\middleware\Auth::class, // 依赖已解析 body 和 session
\app\middleware\CheckPermission::class, // 必须紧跟 Auth,不能被日志/语言包隔开
\think\middleware\Lang::class, // 需在 SessionInit 之后、路由解析之前
\think\middleware\Logger::class, // 应靠后:需完整 action、response 等上下文
];
⚠️ 错误做法:以为类名带
Auth就自动排前面,或把中间件写在文件末尾就“优先级低”——实际只看数组下标。
路由级中间件默认前置插入,不是追加
当你在路由定义中调用 ->middleware(),例如:
Route::get('user', 'User/index')->middleware([
\app\middleware\JwtAuth::class,
\app\middleware\RateLimit::class
]);
这两个中间件会插在整个全局链最前面,形成:JwtAuth → RateLimit → [全局链] → 控制器
若你本意是“在全局鉴权之后再限流”,那就错了。正确做法是:
- 用
->appendMiddleware()替代->middleware(),强制追加到末尾 - 或者把
RateLimit直接注册进config/middleware.php,靠位置控制时机
多应用或多模块下,中间件作用域必须匹配
启用多应用(app.multi_app = true)时:
- 全局配置
config/middleware.php不生效 - 每个应用需单独维护
app/{name}/middleware.php - 若漏配某个应用的中间件文件,该应用下所有路由都不走对应中间件
检查方式:在对应应用的控制器里 dump(config('middleware')),确认数组内容非空且结构正确。
快速验证实际执行链:开启 middleware_trace
开发环境临时启用调试:
// config/app.php 'middleware_trace' => true,
发起一次请求后,查看响应头 X-Middleware-Stack 字段,例如:X-Middleware-Stack: ForceHttps,ValidatePostSize,ParseJsonBody,Auth,Logger
这个字段反映的是最终进入 handle 流程的中间件顺序,跳过被 return response() 提前终止的项。如果某中间件没出现,先查它是否在 handle() 开头就 return 了,而不是顺序问题。
不复杂但容易忽略
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











