全局中间件在所有请求中无条件执行,注册于kernel.php的$middleware数组,路由匹配前运行;路由中间件仅对匹配路由生效,定义于$routemiddleware并需显式调用,执行于路由匹配后、控制器前。

全局中间件在所有请求里无条件执行
它注册在 app/Http/Kernel.php 的 $middleware 数组里,不管访问哪个路由、是否匹配、有没有控制器,都会走一遍。比如 ValidatePostSize 防止超大上传、TrimStrings 自动清理字符串首尾空格——这些是「基础设施级」操作,必须在路由解析前就完成。
常见错误现象:把本该只用于登录页的权限校验逻辑塞进 $middleware,结果 API 接口也强制跳登录页;或者在全局中间件里调用 $request->route(),但此时路由还没匹配,返回 null 导致报错 Call to a member function middleware() on null。
路由中间件只对匹配到的路由生效
它定义在 $routeMiddleware 里,靠别名(如 'auth')绑定,再通过 ->middleware('auth') 显式挂到某条路由或路由组上。执行时机在路由匹配之后、控制器运行之前,此时 $request->route() 可安全使用,也能拿到 route()->action['controller'] 等信息。
使用场景包括:给后台路由加 auth + verified,给 API 路由加 throttle:api,或者给某个资源路由单独加日志中间件。参数差异明显:auth 不带参数,can:delete,App\Models\Post 带两个参数,role:admin,editor 支持多角色——这些都依赖路由上下文才能解析。
执行顺序决定它们能不能互相替代
全局中间件永远最先执行,然后是中间件组(如 web 或 api),最后才是路由中间件。这个洋葱模型不可逆:
- 全局中间件看不到路由信息,不能做「仅对 /admin/* 生效」的判断
- 路由中间件无法拦截未匹配的 404 请求(因为根本没走到路由层)
- 如果在全局中间件里抛出异常,后续所有中间件和路由都不会执行;而路由中间件抛异常,至少前面的全局逻辑已跑完(比如日志、CORS 头已设)
性能影响也很实在:全局中间件每请求必跑,哪怕只是访问 /robots.txt;路由中间件则按需加载,Laravel 会跳过未使用的类,autoload 开销更低。
最容易被忽略的坑:中间件里调用 $next() 的位置
所有中间件都靠 $next($request) 把控制权往下传。但全局中间件里写 return $next($request)->withHeaders([...]) 是安全的;而路由中间件若在 $next($request) 之后还试图修改响应头,可能被更外层的中间件覆盖(比如 HandleCors 在最外层,会重写 Access-Control-Allow-Origin)。
另一个隐形陷阱:在 $routeMiddleware 中注册了一个中间件类,但忘了在路由中显式调用 ->middleware('xxx'),它就完全不会执行——不像全局中间件,不声明就不会存在。











