本文目录导读:

非常重要。 在 Laravel 中,中间件的执行顺序直接决定了请求的生命周期,顺序错误会导致逻辑错误、安全漏洞,甚至请求直接失败。
顺序决定了谁先“看到”请求,谁后“看到”请求。
顺序影响什么?
- 执行优先级:先执行的中间件会先于后执行的中间件进行逻辑处理,比如先做身份认证,才能做权限校验。
- 请求/响应修改:如果一个中间件修改了
$request,后面的中间件拿到的就是修改后的数据。 - 短路机制:如果前面的中间件直接返回了响应(例如返回 403),后面的中间件将永远没有机会执行。
中间件的执行顺序规则
Laravel 中间件是有严格层次结构的,按优先级从高到低排列:
- 全局中间件(
app/Http/Kernel.php的$middleware数组):- 所有请求都会先经过这些,通常是
TrustProxies、HandleCors、PreventRequestsDuringMaintenance等。
- 所有请求都会先经过这些,通常是
- 路由组中间件(
$middlewareGroups,如web、api):- 分配给特定路由组的中间件,这里包含
StartSession、EncryptCookies等。
- 分配给特定路由组的中间件,这里包含
- 路由特定中间件(在路由定义或控制器构造函数中指定的):
优先级最低,只有当请求匹配该路由时才会执行。
关键点:全局中间件执行于路由组,路由组执行于路由特定中间件。
顺序错误的常见后果
- 认证失败:
auth:api放在throttle之后,未登录的用户也可能被限流,但如果是auth在前,未登录用户会在限流前被拦截。 - CSRF 过滤失效:如果在
web组中,VerifyCsrfToken放在了StartSession前面,会导致 CSRF Token 无法读取。 - 权限判断错误:
can:(权限)中间件放在auth之前,那么用户未登录时会抛出“未认证”错误,而不是返回 401 或跳转登录页。 - 响应格式错误:
ConvertEmptyStringsToNull放在业务逻辑中间件之后,可能业务中间件拿到的还是空字符串,导致逻辑判断错误。
如何查看和自定义顺序?
在 app/Http/Kernel.php 文件中,你可以清晰地看到并调整:
protected $middleware = [
// 全局中间件 (所有请求)
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
...
];
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
...
],
'api' => [
'throttle:api', // 限流
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
在数组中的顺序就是实际执行顺序,从上到下依次执行。
实战案例:auth 和 throttle 的顺序
假设你有这个路由配置:
Route::middleware(['auth', 'throttle:60,1'])->get('/data', function(){
return 'secret data';
});
- 正确(推荐):先
auth后throttle→ 未登录用户直接被拦截,登录用户限流,这更安全,避免了恶意未登录请求消耗服务器资源。 - 错误:先
throttle后auth→ 未登录用户可以先被限流,限流后返回 429(请求过多),这可能导致合法用户被误伤,逻辑不分明。
最佳实践建议
- 先做“认证”,再做“授权(权限)”。
- 先做“请求预处理”(如 CORS、JSON 解析),再做“业务逻辑”。
- 把“响应修改”中间件放在后面(如
Cors应在最外层,以便统一给响应添加头)。 - 分组管理:将确实需要特殊顺序的中间件放入路由组里,而不是全部堆在全局。
中间件顺序绝对是 Laravel 项目中的关键细节。 它类似于流水线中的关卡顺序,放错位置会导致整个请求流程混乱,在开发时,建议先在 Kernel.php 里明确规划好每一层的作用,再编写业务逻辑,这样能避免很多棘手的 Bug。