Laravel路由中间件?中间件如何分配路由?

31次阅读

Laravel路由中间件是请求到达控制器前的过滤机制,可用于认证、授权、日志等操作。可通过全局、路由组、单个路由或控制器方式分配,执行顺序遵循“从外到内”原则:全局中间件 → 路由组中间件 → 单个/控制器中间件,响应时则逆序执行后续逻辑。

Laravel路由中间件?中间件如何分配路由?

Laravel的路由中间件,在我看来,就像是HTTP请求抵达你应用核心逻辑(比如控制器方法)前的一道道关卡或守卫。它的核心作用,就是让你能在请求真正被处理之前或之后,执行一些预设的操作。至于如何分配路由,其实Laravel给了我们很多灵活的方式,无论是全局、针对一组路由,还是某个特定的路由,甚至是在控制器内部,都能精准地挂载中间件。

解决方案

要说如何在Laravel里分配中间件给路由,其实方法挺多的,每种都有它适用的场景。我个人觉得,理解这些不同的分配方式,是掌握Laravel请求生命周期的关键一步。

  1. 全局中间件 (Global Middleware) 这是最粗放也最直接的方式,任何进入你应用的HTTP请求都会经过这些中间件。你可以在

    app/Http/Kernel.php

    文件的

    $middleware

    属性中定义它们。

    // app/Http/Kernel.php  protected $middleware = [     AppHttpMiddlewareTrustProxies::class,     AppHttpMiddlewarePreventRequestsDuringMaintenance::class,     IlluminateFoundationHttpMiddlewareValidatePostSize::class,     AppHttpMiddlewareTrimStrings::class,     IlluminateFoundationHttpMiddlewareConvertEmptyStringsToNull::class,     // AppHttpMiddlewareEncryptCookies::class, // 假设我不想所有请求都加密cookie     // ... 其他全局中间件 ];

    坦白讲,全局中间件我用得不多,通常是那些对所有请求都生效的基础性操作,比如处理CORS、维护模式检查或者一些基础的请求数据处理。

  2. 路由组中间件 (Route Group Middleware) 这是我个人最常用的一种方式,尤其是在构建API或者需要对一组相关路由应用相同策略时。通过

    Route::middleware()

    方法,你可以将一个或多个中间件应用到一个路由组上。

    // routes/web.php 或 routes/api.php  Route::middleware(['auth', 'verified'])->group(function () {     Route::get('/dashboard', function () {         // 需要认证且邮箱已验证才能访问     });      Route::get('/profile', 'UserProfileController@show'); });  // 也可以是多个中间件链式调用 Route::middleware('auth')->middleware('throttle:60,1')->group(function () {     Route::post('/order', 'OrderController@store'); });

    这种方式的好处在于,它能让你的路由文件看起来更整洁,逻辑也更清晰。想象一下,如果每个路由都单独写

    ->middleware('auth')

    ,那代码得多冗余啊。

  3. 单个路由中间件 (Individual Route Middleware) 如果你只想给某个特定的路由应用中间件,直接在路由定义后面链式调用

    middleware()

    方法就行。

    // routes/web.php  Route::get('/admin/settings', 'AdminController@showSettings')->middleware('admin');  Route::post('/logout', 'AuthLoginController@logout')->middleware('auth');

    这个方法很直观,适合那些有特殊需求的单个路由。但如果多个路由有相同需求,我肯定会考虑用路由组。

  4. 控制器中间件 (Controller Middleware) 有时候,你可能希望一个控制器里的所有方法,或者部分方法,都经过某个中间件处理。这时候,可以在控制器的构造函数里定义。

    // app/Http/Controllers/PostController.php  class PostController extends Controller {     public function __construct()     {         $this->middleware('auth'); // 所有方法都需要认证         $this->middleware('can:update,post')->only('edit', 'update'); // 只有edit和update方法需要授权         $this->middleware('log.access')->except('show'); // 除了show方法,其他方法都要记录访问日志     }      public function index() { /* ... */ }     public function create() { /* ... */ }     public function store() { /* ... */ }     public function show(Post $post) { /* ... */ }     public function edit(Post $post) { /* ... */ }     public function update(Request $request, Post $post) { /* ... */ }     public function destroy(Post $post) { /* ... */ } }

    我个人觉得控制器中间件非常方便,尤其是在处理资源控制器(Resource Controllers)时,它能让你在控制器层面进行更细粒度的控制,避免了路由文件过于臃肿。

    only()

    except()

    方法的组合拳,更是让这种控制变得异常强大。

Laravel中间件的执行顺序是怎样的?

说实话,中间件的执行顺序是个常常让人感到困惑,但又极其重要的问题。理解它,能帮你更好地调试请求流程,避免一些意想不到的行为。在我看来,Laravel中间件的执行顺序,可以大致概括为“从外到内,再从内到外”的原则。

具体来说,当一个HTTP请求进入Laravel应用时,它会首先经过

app/Http/Kernel.php

$middleware

属性里定义的全局中间件。这些中间件是所有请求的“必经之路”,它们按照你在数组中定义的顺序依次执行。

紧接着,如果请求命中了某个路由组,那么这个路由组上挂载的中间件会开始执行。这些中间件的执行顺序,就是你在

Route::middleware([...])

数组中定义的顺序。

再往里走,如果路由组内的某个具体路由还单独挂载了中间件,或者你是在控制器构造函数里为特定方法定义了中间件,那么这些中间件会在路由组中间件之后执行。同样,它们的顺序也取决于定义时的顺序。

总结一下,一个请求的中间件执行顺序大概是:

  1. 全局中间件 (Kernel.php
    $middleware

    )

  2. 路由中间件组 (Kernel.php
    $middlewareGroups

    ,如果路由使用了组别,如

    web

    api

    )

  3. 路由组中间件 (
    Route::middleware([...])->group()

    )

  4. 单个路由中间件 (
    ->middleware()

    ) 或 控制器中间件 (

    $this->middleware()

    )

值得一提的是,中间件的

handle

方法在请求到达控制器之前执行,而中间件中的

terminate

方法(如果你定义了的话)则是在HTTP响应发送给浏览器之后才执行。这意味着

terminate

方法非常适合做一些清理、日志记录等不影响响应速度的操作。

// app/Http/Kernel.php protected $middleware = [     // 1. 全局中间件 A     AppHttpMiddlewareTrustProxies::class,     // 2. 全局中间件 B     AppHttpMiddlewarePreventRequestsDuringMaintenance::class, ];  protected $middlewareGroups = [     'web' => [         // 3. Web组中间件 A         AppHttpMiddlewareEncryptCookies::class,         // 4. Web组中间件 B         IlluminateSessionMiddlewareStartSession::class,     ],     'api' => [         // 5. API组中间件 A         LaravelSanctumHttpMiddlewareEnsureFrontendRequestsAreStateful::class,         // 6. API组中间件 B         'throttle:api',     ], ];  // routes/web.php Route::middleware(['auth', 'check.role:admin'])->group(function () {     // 7. 路由组中间件 auth     // 8. 路由组中间件 check.role:admin     Route::get('/admin', 'AdminController@index')->middleware('log.activity');     // 9. 单个路由中间件 log.activity });

所以,请求的实际路径是:全局A -> 全局B -> Web组A -> Web组B -> auth -> check.role:admin -> log.activity -> 控制器方法。然后响应回来的时候,这个顺序会反过来执行中间件的后续逻辑(如果

handle

方法中有

$next($request)

之后的代码)和

terminate

方法。这种层层嵌套的机制,是Laravel中间件强大灵活的基础。

如何在Laravel中创建和注册自定义中间件?

创建和注册自定义中间件,是Laravel开发中非常常见且实用的操作。它允许你根据自己的业务需求,定制请求处理流程中的任何环节。

首先,创建中间件非常简单,Laravel提供了一个Artisan命令:

Laravel路由中间件?中间件如何分配路由?

Designer

Microsoft推出的图形设计应用程序

Laravel路由中间件?中间件如何分配路由?63

查看详情 Laravel路由中间件?中间件如何分配路由?

php artisan make:middleware MyCustomLogger

执行这个命令后,Laravel会在

app/Http/Middleware

目录下生成一个名为

MyCustomLogger.php

的文件。文件内容大致如下:

<?php  namespace AppHttpMiddleware;  use Closure; use IlluminateHttpRequest; use SymfonyComponentHttpFoundationResponse;  class MyCustomLogger {     /**      * Handle an incoming request.      *      * @param  IlluminateHttpRequest  $request      * @param  Closure(IlluminateHttpRequest): (SymfonyComponentHttpFoundationResponse)  $next      * @return SymfonyComponentHttpFoundationResponse      */     public function handle(Request $request, Closure $next): Response     {         // 在请求到达控制器之前执行的逻辑         // 比如,记录请求信息         Log::info('Incoming request: ' . $request->method() . ' ' . $request->fullUrl());          $response = $next($request); // 将请求传递给下一个中间件或控制器          // 在请求离开控制器之后执行的逻辑         // 比如,记录响应状态码         Log::info('Outgoing response status: ' . $response->getStatusCode());          return $response;     } }
handle

方法是中间件的核心。它接收两个参数:

$request

(当前的HTTP请求)和

$next

(一个闭包,代表请求流中的下一个处理者,可能是另一个中间件,也可能是控制器)。

  • $next($request)

    之前的代码,会在请求到达控制器之前执行。

  • $next($request)

    之后的代码,会在控制器处理完请求并生成响应之后,但在响应返回给客户端之前执行。

接下来是注册。自定义中间件创建好之后,你需要让Laravel知道它的存在。这通常在

app/Http/Kernel.php

文件中完成。

如果你想将它注册为路由中间件(即可以通过别名在路由或控制器中使用),你需要把它添加到

$routeMiddleware

属性中:

// app/Http/Kernel.php  protected $routeMiddleware = [     'auth' => AppHttpMiddlewareAuthenticate::class,     'verified' => AppHttpMiddlewareEnsureEmailIsVerified::class,     'my.logger' => AppHttpMiddlewareMyCustomLogger::class, // 注册你的自定义中间件     // ... 其他路由中间件 ];

注册后,你就可以像使用内置中间件一样,在路由或控制器中通过

my.logger

这个别名来应用它了:

Route::get('/some-path', 'SomeController@index')->middleware('my.logger');

或者,如果你想让它成为全局中间件,那么就把它添加到

$middleware

属性中:

// app/Http/Kernel.php  protected $middleware = [     // ...     AppHttpMiddlewareMyCustomLogger::class, // 作为全局中间件注册 ];

一旦注册为全局中间件,所有进入应用的请求都会经过

MyCustomLogger

处理。选择哪种注册方式,完全取决于你的业务需求。大多数情况下,我更倾向于注册为路由中间件,这样可以更灵活地控制哪些请求需要经过我的自定义逻辑。

Laravel中间件在实际项目中常见的应用场景有哪些?

在实际的Laravel项目开发中,中间件几乎无处不在,它的设计哲学就是为了让你能优雅地解耦请求处理前的各种“横切关注点”。在我看来,中间件是构建健壮、可维护的Laravel应用不可或缺的一部分。

这里我列举一些我个人在项目中经常用到,或者觉得非常典型的应用场景:

  1. 用户认证 (Authentication): 这是最常见也是最重要的应用。Laravel内置的

    auth

    中间件就是为此而生。它会检查用户是否已登录。如果未登录,通常会重定向到登录页面或返回未认证的响应。

    Route::middleware('auth')->group(function () {     Route::get('/dashboard', 'DashboardController@index');     // ... 其他需要登录才能访问的路由 });

    对于API,

    auth:api

    auth:sanctum

    则是验证API令牌或会话的利器。

  2. 用户授权 (Authorization): 在用户认证之后,你可能还需要检查用户是否有权限执行某个操作。Laravel的

    can

    中间件结合了策略(Policies)或门面(Gates)来实现授权。

    Route::get('/posts/{post}/edit', 'PostController@edit')->middleware('can:update,post');

    这里

    can:update,post

    会检查当前用户是否有权限更新传入的

    post

    模型。

  3. CSRF 保护 (CSRF Protection): Laravel的

    VerifyCsrfToken

    中间件是默认开启的全局中间件,它能有效防止跨站请求伪造攻击,确保所有非GET请求都带有有效的CSRF令牌。这个真的非常省心,我们几乎不用操心。

  4. 请求限流 (Rate Limiting): 对于API接口,为了防止恶意攻击或资源滥用,限流是必不可少的。Laravel的

    throttle

    中间件可以轻松实现。

    Route::middleware('throttle:60,1')->group(function () { // 每分钟最多60次请求     Route::post('/api/submit-form', 'ApiController@submit'); });

    这能很好地保护你的后端服务。

  5. 维护模式 (Maintenance Mode): 当你的应用需要进行升级或维护时,

    PreventRequestsDuringMaintenance

    中间件能让所有请求都重定向到一个维护页面,直到你关闭维护模式。这也是一个默认的全局中间件,非常实用。

  6. 日志记录与审计 (Logging & Auditing): 我上面自定义的

    MyCustomLogger

    就是一个很好的例子。你可以在中间件中记录请求的详细信息(如IP、User-Agent、请求路径、请求参数),或者记录响应状态、执行时间等,用于监控和审计。

  7. API 密钥验证 (API Key Validation): 如果你在构建一个公共API,可能需要验证请求头中是否包含有效的API Key。

    // app/Http/Middleware/VerifyApiKey.php public function handle(Request $request, Closure $next): Response {     if (!$request->header('X-API-Key') || !$this->isValidApiKey($request->header('X-API-Key'))) {         return response()->json(['message' => 'Unauthorized: Invalid API Key'], 401);     }     return $next($request); }  // routes/api.php Route::middleware('verify.api.key')->group(function () {     Route::get('/api/data', 'ApiController@getData'); });
  8. 数据预处理与清理 (Data Preprocessing & Sanitization): 例如,将所有字符串输入自动去除首尾空格 (

    TrimStrings

    中间件),或者将空字符串转换为

    null

    (

    ConvertEmptyStringsToNull

    中间件)。这些都是Laravel默认提供的,极大提高了开发效率和数据一致性。

  9. 语言本地化 (Localization): 根据用户的请求头(如

    Accept-Language

    )或者URL参数,动态设置应用的语言环境。

    // app/Http/Middleware/SetLocale.php public function handle(Request $request, Closure $next): Response {     if ($request->hasHeader('Accept-Language')) {         App::setLocale($request->header('Accept-Language'));     }     return $next($request); } // ... 注册并应用

    这些场景只是冰山一角。中间件的强大之处在于它提供了一个统一且可扩展的机制,来处理请求生命周期中的各种通用逻辑,让你的控制器能更专注于业务逻辑本身,从而实现代码的清晰、解耦和高内聚。

以上就是Laravel路由中间件?中间件如何分配路由?的详细内容,更多请关注php laravel js json go cookie 浏览器 app access session 后端 ai php laravel 中间件 csrf NULL Resource 构造函数 Logging 字符串 接口 闭包 this http

php laravel js json go cookie 浏览器 app access session 后端 ai php laravel 中间件 csrf NULL Resource 构造函数 Logging 字符串 接口 闭包 this http

text=ZqhQzanResources