本文目录导读:

在 Laravel 中,中间件的执行顺序遵循“洋葱模型”或“栈”模型,即在请求进入和响应返回时,中间件按特定顺序执行。
核心执行顺序规则
全局中间件最先执行
在 app/Http/Kernel.php 的 $middleware 属性中定义的中间件,会在所有路由中间件之前执行。
路由中间件按组和优先级执行
- StartKernel(框架核心中间件)→ 全局中间件 → 路由中间件(按注册顺序)
具体执行流程
请求进入时的执行顺序
请求 → StartKernel → 全局中间件 → 路由中间件组 → 路由特定中间件 → 控制器
响应返回时的执行顺序(反向)
控制器 → 路由特定中间件 → 路由中间件组 → 全局中间件 → StartKernel → 响应
中间件定义位置与优先级
app/Http/Kernel.php 中的三个属性
protected $middleware = [
// 1. 全局中间件(最先执行)
\App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
];
protected $middlewareGroups = [
'web' => [
// 2. web 组中间件
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// \Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
// 3. api 组中间件
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
protected $routeMiddleware = [
// 4. 路由特定中间件(最后执行)
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
实际执行顺序示例
假设路由定义为:
Route::get('/admin', function () {
// 控制器逻辑
})->middleware(['web', 'auth', 'admin']);
执行顺序:
StartKernel(框架核心)
2. 全局中间件(TrustHosts, TrustProxies, HandleCors...)
3. web 组中间件(EncryptCookies, StartSession...)
4. 'auth' 中间件
5. 'admin' 中间件
6. 控制器
7. 'admin' 中间件(返回时)
8. 'auth' 中间件(返回时)
9. web 组中间件(返回时)
10. 全局中间件(返回时)
11. StartKernel(返回时)
中间件在控制器中的执行顺序
如果在控制器中指定多个中间件:
public function __construct()
{
$this->middleware('auth');
$this->middleware('log')->only('index');
$this->middleware('subscribed')->except('store');
}
执行顺序为:log → subscribed → auth(按定义顺序的倒序执行)
特殊情况
Terminable 中间件
实现 terminate() 方法的中间件,在响应发送到浏览器后执行:
public function terminate($request, $response)
{
// 在响应发送后执行
}
优先级(Priority)
可以设置中间件的优先级:
protected $middlewarePriority = [
\Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
];
实际应用建议
- 性能敏感中间件(如缓存、限流)应尽早执行
- 认证中间件(如 auth)应在路由组中间件之后
- 数据验证中间件(如 TrimStrings)应在最外层
理解这个执行顺序对于调试中间件问题、优化性能和确保安全至关重要,你可以使用 php artisan route:list 来查看每个路由的中间件执行顺序。