中间件执行顺序由三层注册位置决定:全局中间件($middleware)最先执行,中间件组($middlewareGroups)次之,路由级中间件(->middleware())最后执行;顺序即优先级,调整数组位置最直接有效。

中间件优先级不是“调”出来的,而是“排”出来的——顺序即优先级,改数组位置就是最直接有效的调整方式。
中间件执行顺序由哪几个地方决定?
不是靠某个配置项“设置优先级”,而是三层注册位置共同决定最终执行顺序:
- 全局中间件(
$middleware)最先执行,定义在app/Http/Kernel.php的protected $middleware = [...]数组中,从上到下依次运行 - 中间件组(如
web或api)次之,定义在$middlewareGroups中,比如web组默认包含EncryptCookies、StartSession等 - 路由级中间件(
->middleware(...))最后执行,只作用于指定路由或分组
也就是说:你写在 $middleware 里的第 1 个类,永远比 web 组里的第一个还早;而你在某条 Route::get(...)->middleware('auth') 上加的中间件,一定在所有全局和组中间件之后才跑。
为什么把 Authenticate 放错位置会跳过登录校验?
常见错误现象:用户没登录,却能访问 /admin 页面,甚至控制器里 auth()->user() 居然不为 null —— 实际是 session 或 token 解析失败后 fallback 到了空用户。
- 如果
StartSession在Authenticate后面,认证中间件根本读不到 session 数据,自然无法判断是否已登录 - 如果
EncryptCookies被挪到Authenticate后面,加密后的 cookie 还没解密,VerifyCsrfToken和Authenticate都可能因无法读取原始值而失效 - 自定义中间件依赖
Auth::user(),但把它放在Authenticate前面,就会拿到 null,引发 NPE 或逻辑跳过
所以别只盯着自己写的中间件,得看它依赖哪些 Laravel 内置中间件的状态——它们必须先执行。
怎么安全地调整中间件顺序?
不要靠猜,用 $middlewarePriority 显式声明关键中间件层级(Laravel 5.6+ 支持),它不改变执行顺序,但让框架知道哪些中间件“不能乱动”:
- 在
app/Http/Kernel.php中添加属性:protected $middlewarePriority = [ \Illuminate\Session\Middleware\StartSession::class, \App\Http\Middleware\Authenticate::class, \App\Http\Middleware\CheckRole::class, ]; - 这个数组只影响“当多个中间件同时注册时,谁该被提到前面”,比如你在路由上加了
auth和throttle,而$middlewarePriority里Authenticate在ThrottleRequests前,那它就会被自动前置 - 但注意:
$middlewarePriority不会把你手动写在$middleware底部的Authenticate“拉上来”——它只起协调作用,主顺序还是靠数组位置
真正容易被忽略的点是:子域名路由和中间件无关,但和路由匹配顺序强相关;而中间件本身又依赖路由匹配后的请求上下文(比如 Request::route())。所以如果你发现中间件里拿不到 route 参数,先检查是不是子域名路由写在了根域名后面,导致压根没进对的路由分组——那中间件根本不会触发。











