中间件是 Laravel 中实现请求过滤的核心机制,它可以在请求到达控制器之前或响应返回客户端之后执行特定逻辑。 本章将系统讲解如何创建自定义中间件,并将其注册到应用中。
中间件为应用程序提供了一个方便的机制,用于过滤进入应用的 HTTP 请求。例如,Laravel 内置了身份验证中间件,用于验证用户是否已登录。 如果用户未登录,中间件会将用户重定向到登录页面;如果用户已登录,则允许请求继续执行。
中间件可以用于:
使用 Artisan 命令 make:middleware 可以快速生成中间件:
php artisan make:middleware CheckAge
该命令会在 app/Http/Middleware 目录下创建 CheckAge.php 文件,内容如下:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class CheckAge
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
return $next($request);
}
}
Closure 类型提示,并返回 Response 对象。你可以根据需要修改 handle 方法的逻辑。
中间件的核心是 handle 方法。它接收当前请求 $request 和一个闭包 $next,闭包代表将请求传递到下一个中间件或控制器。
以下是一个检查年龄的中间件示例:
public function handle(Request $request, Closure $next): Response
{
if ($request->age < 18) {
return redirect('home');
}
return $next($request);
}
如果年龄小于 18,中间件返回重定向响应,阻止请求继续;否则调用 $next($request) 将请求传递给下一个中间件。
中间件还可以接收额外参数,在路由中定义时传递:
public function handle(Request $request, Closure $next, string $role): Response
{
if (! $request->user() || ! $request->user()->hasRole($role)) {
abort(403);
}
return $next($request);
}
注册时需要指定参数值,例如:->middleware('role:admin')。
创建中间件后,需要将其注册到应用中才能生效。Laravel 提供了三种注册方式:全局中间件、路由中间件和中间件组。
全局中间件会在每个 HTTP 请求中自动执行。注册位置在 app/Http/Kernel.php 文件的 $middleware 属性中:
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
// 添加自定义全局中间件
\App\Http\Middleware\CheckAge::class,
];
Kernel 类可能简化了中间件结构,但全局中间件的注册方式基本一致。如果 Kernel.php 不存在,可检查 bootstrap/app.php 中的中间件配置。
路由中间件只针对特定路由执行,需要在 Kernel.php 的 $routeMiddleware 属性中为中间件分配一个键名:
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'age' => \App\Http\Middleware\CheckAge::class, // 自定义路由中间件
];
然后在路由中使用 middleware 方法:
Route::get('/dashboard', function () {
// 只有年龄符合要求的用户才能访问
})->middleware('age');
也可以传递参数:->middleware('age:18'),中间件会接收 18 作为参数。
中间件组允许将多个中间件组合在一起,方便批量应用。Laravel 内置了 web 和 api 两个中间件组。可以在 Kernel.php 的 $middlewareGroups 中定义自定义组:
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// ...
],
'api' => [
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
// 自定义中间件组
'admin' => [
'auth',
'age:18',
\App\Http\Middleware\AdminRole::class,
],
];
在路由中使用组:Route::middleware('admin')->group(function () { ... });
Kernel 类可能不再存在,中间件配置迁移到了 bootstrap/app.php 中。如果使用新版,请参考以下配置方式。
在 Laravel 11 中,中间件的注册方式有所简化,主要配置集中在 bootstrap/app.php 文件中:
->withMiddleware(function (Middleware $middleware) {
// 全局中间件
$middleware->append([
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
]);
// 路由中间件别名
$middleware->alias([
'auth' => \App\Http\Middleware\Authenticate::class,
'age' => \App\Http\Middleware\CheckAge::class,
]);
// 中间件组
$middleware->group('web', [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
// ...
]);
})
使用时与旧版本相同,路由中通过别名引用。
如果中间件需要在响应发送到浏览器后执行一些任务(如记录日志),可以实现 terminate 方法:
class LogRequestMiddleware
{
public function handle(Request $request, Closure $next)
{
return $next($request);
}
public function terminate(Request $request, Response $response)
{
// 响应发送后执行,如记录日志
Log::info('请求处理完成', [
'url' => $request->url(),
'status' => $response->getStatusCode(),
]);
}
}
只有全局中间件和路由中间件(且通过 Kernel 注册)支持 terminate 方法。在 Laravel 11 中,终止中间件的注册方式可能略有不同,但原理一致。
以下是一个完整的中间件创建、注册和使用示例:
1. 创建中间件:
php artisan make:middleware CheckRole
2. 编写中间件逻辑:
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class CheckRole
{
public function handle(Request $request, Closure $next, string $role): Response
{
if (! $request->user() || ! $request->user()->hasRole($role)) {
abort(403, '无权限访问');
}
return $next($request);
}
}
3. 注册中间件(Laravel 11 方式):
在 bootstrap/app.php 中:
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'role' => \App\Http\Middleware\CheckRole::class,
]);
})
4. 在路由中使用:
Route::get('/admin/dashboard', function () {
return '管理员仪表盘';
})->middleware('role:admin');
$this->middleware() 方法,例如:$this->middleware('auth');,支持 only 和 except 参数。
bootstrap/app.php 中,使用 withMiddleware 方法进行配置。请参照本章的新版说明。
中间件是 Laravel 中强大而灵活的请求过滤机制。通过 Artisan 命令可以快速创建中间件,并在 bootstrap/app.php(Laravel 11)或 Kernel.php(旧版)中注册。
掌握中间件的创建与注册,能够让你轻松实现身份验证、权限控制、日志记录等横切关注点,保持代码整洁。
下一章我们将学习会话管理,进一步掌握用户状态维护的技巧。