跳转到主要内容

什么是中间件

中间件是一种检查、过滤到达应用的 HTTP 请求的机制。 你可以在请求到达控制器前后插入处理逻辑。 比如 Laravel 内置了认证中间件。 当用户未认证时,会重定向到登录页面;若已认证,则允许请求继续进入应用内部。 除认证外,还可以为日志记录、CSRF 保护、限流等各种目的编写中间件。关于 Laravel 13 CSRF 保护的详细内容,请参阅 CSRF 保护
用户自定义的中间件通常放在 app/Http/Middleware 目录下。

内置中间件

Laravel 默认准备了 webapi 两个中间件组。 routes/web.php 会自动应用 web 组,routes/api.php 会自动应用 api 组。
web 中间件组
EncryptCookies
AddQueuedCookiesToResponse
StartSession
ShareErrorsFromSession
PreventRequestForgery(CSRF 保护)
SubstituteBindings
对常用中间件,还设置了别名,可以用简短的名字引用。
别名中间件
authIlluminate\Auth\Middleware\Authenticate
guestIlluminate\Auth\Middleware\RedirectIfAuthenticated
verifiedIlluminate\Auth\Middleware\EnsureEmailIsVerified
throttleIlluminate\Routing\Middleware\ThrottleRequests

创建中间件

使用 make:middleware Artisan 命令创建新的中间件。
php artisan make:middleware EnsureTokenIsValid
会生成 app/Http/Middleware/EnsureTokenIsValid.php。 在 handle 方法中编写处理请求的逻辑。
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureTokenIsValid
{
    /**
     * 处理传入的请求
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        if ($request->input('token') !== 'my-secret-token') {
            return redirect('/home');
        }

        return $next($request);
    }
}
调用 $next($request) 会将请求交给应用的下一环处理。 若不满足条件,可以返回重定向或响应,从而阻止请求继续。

请求前后的处理

中间件可以在请求之前之后执行逻辑。
// 在请求前处理
public function handle(Request $request, Closure $next): Response
{
    // 前置处理写在这里

    return $next($request);
}
// 在响应后处理
public function handle(Request $request, Closure $next): Response
{
    $response = $next($request);

    // 后置处理写在这里

    return $response;
}

注册中间件

全局中间件

若希望所有请求都执行该中间件,请在 bootstrap/app.phpwithMiddleware 中添加到全局栈。
// bootstrap/app.php
use App\Http\Middleware\EnsureTokenIsValid;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->append(EnsureTokenIsValid::class);
    });
append 追加到栈末尾。要放到最前面请用 prepend

对路由应用中间件

若只对特定路由应用中间件,可在路由定义上调用 middleware
use App\Http\Middleware\EnsureTokenIsValid;

Route::get('/profile', function () {
    // ...
})->middleware(EnsureTokenIsValid::class);
要应用多个中间件,用数组传入。
Route::get('/', function () {
    // ...
})->middleware([First::class, Second::class]);
若要在特定路由上排除某个中间件,可使用 withoutMiddleware
use App\Http\Middleware\EnsureTokenIsValid;

Route::middleware([EnsureTokenIsValid::class])->group(function () {
    Route::get('/', function () {
        // 应用了该中间件
    });

    Route::get('/profile', function () {
        // 该路由排除中间件
    })->withoutMiddleware([EnsureTokenIsValid::class]);
});

中间件别名

可以为较长的类名设置短别名。在 bootstrap/app.php 中配置。
// bootstrap/app.php
use App\Http\Middleware\EnsureUserIsSubscribed;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->alias([
            'subscribed' => EnsureUserIsSubscribed::class,
        ]);
    });
使用别名应用到路由:
Route::get('/profile', function () {
    // ...
})->middleware('subscribed');

中间件组

将多个中间件归为一个键,便于统一应用到路由。 在 bootstrap/app.php 中使用 appendToGroupprependToGroup
// bootstrap/app.php
use App\Http\Middleware\First;
use App\Http\Middleware\Second;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->appendToGroup('group-name', [
            First::class,
            Second::class,
        ]);
    });
分组可像普通中间件一样应用到路由。
Route::get('/', function () {
    // ...
})->middleware('group-name');

Route::middleware(['group-name'])->group(function () {
    // ...
});
要向已有的 webapi 分组添加中间件,可使用专用方法。
// bootstrap/app.php
use App\Http\Middleware\EnsureUserIsSubscribed;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->web(append: [
            EnsureUserIsSubscribed::class,
        ]);
    });

中间件参数

中间件可以接收额外参数。 在 handle 方法的 $next 参数之后添加参数即可。
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureUserHasRole
{
    public function handle(Request $request, Closure $next, string $role): Response
    {
        if (! $request->user()->hasRole($role)) {
            return redirect('/home');
        }

        return $next($request);
    }
}
在路由定义中,中间件名和参数用 : 分隔。
use App\Http\Middleware\EnsureUserHasRole;

Route::put('/post/{id}', function (string $id) {
    // ...
})->middleware(EnsureUserHasRole::class.':editor');
多个参数用逗号分隔。
Route::put('/post/{id}', function (string $id) {
    // ...
})->middleware(EnsureUserHasRole::class.':editor,publisher');

实用示例:认证检查中间件

一个简单的示例:把未登录用户重定向到登录页。
php artisan make:middleware RedirectIfNotAuthenticated
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class RedirectIfNotAuthenticated
{
    public function handle(Request $request, Closure $next): Response
    {
        if (! $request->user()) {
            return redirect('/login');
        }

        return $next($request);
    }
}
应用到路由:
Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(RedirectIfNotAuthenticated::class);
Laravel 已内置用于认证的 auth 中间件。自行实现前请先确认现有中间件能否满足需求。

下一步

HTTP 请求

学习如何在控制器中接收请求数据。
最后修改于 2026年7月13日