Laravel 13 中间件新特性详解

摘要

Laravel 13 对中间件系统进行了增强,提供了更灵活的中间件定义和使用方式。本文将深入讲解 Laravel 13 的中间件新特性,包括:

  • 中间件属性详解
  • 中间件组与优先级
  • 终止中间件
  • 中间件参数
  • 实战案例与最佳实践

本文适合希望掌握 Laravel 13 中间件新特性的开发者。

1. 中间件属性

1.1 类级别中间件

1
2
3
4
5
6
7
use Illuminate\Routing\Attributes\Controllers\Middleware;

#[Middleware('auth')]
class DashboardController extends Controller
{
// 所有方法都需要认证
}

1.2 方法级别中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
class UserController extends Controller
{
#[Middleware('auth')]
public function profile()
{
// 需要认证
}

public function public()
{
// 不需要认证
}
}

1.3 多个中间件

1
2
3
4
5
#[Middleware(['auth', 'verified', 'admin'])]
class AdminController extends Controller
{
// 需要认证、邮箱验证、管理员权限
}

1.4 中间件参数

1
2
3
4
5
6
7
8
9
10
11
#[Middleware('throttle:60,1')]
class ApiController extends Controller
{
// 每分钟 60 次请求
}

#[Middleware('role:admin,editor')]
class ContentController extends Controller
{
// 需要 admin 或 editor 角色
}

2. 自定义中间件

2.1 创建中间件

1
php artisan make:middleware CheckAge

2.2 中间件实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class CheckAge
{
public function handle(Request $request, Closure $next)
{
if ($request->age < 18) {
return redirect('home');
}

return $next($request);
}
}

2.3 后置中间件

1
2
3
4
5
6
7
8
9
10
11
class AfterMiddleware
{
public function handle(Request $request, Closure $next)
{
$response = $next($request);

// 在响应发送后执行

return $response;
}
}

2.4 终止中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class TerminatingMiddleware
{
public function handle(Request $request, Closure $next)
{
return $next($request);
}

public function terminate(Request $request, $response)
{
// 在响应发送后执行
Log::info('Request completed', [
'url' => $request->fullUrl(),
'status' => $response->status(),
]);
}
}

3. 中间件参数

3.1 定义参数

1
2
3
4
5
6
7
8
9
10
11
class RoleMiddleware
{
public function handle(Request $request, Closure $next, ...$roles)
{
if (!in_array($request->user()->role, $roles)) {
abort(403);
}

return $next($request);
}
}

3.2 使用参数

1
2
3
4
5
#[Middleware('role:admin,editor')]
public function admin()
{
// 需要 admin 或 editor 角色
}

4. 中间件组

4.1 定义组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// app/Http/Kernel.php
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],

'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];

4.2 使用组

1
2
3
4
5
6
7
8
9
10
11
#[Middleware('web')]
class WebController extends Controller
{
// 使用 web 中间件组
}

#[Middleware('api')]
class ApiController extends Controller
{
// 使用 api 中间件组
}

5. 中间件优先级

5.1 全局优先级

1
2
3
4
5
6
7
8
9
10
// app/Http/Kernel.php
protected $middlewarePriority = [
\Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class,
\Illuminate\Cookie\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
];

5.2 排除中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#[Middleware('auth')]
class UserController extends Controller
{
public function index()
{
// 需要 auth
}

#[Middleware(except: ['auth'])]
public function public()
{
// 不需要 auth
}
}

6. 实战案例

6.1 API 限流中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;

class RateLimitByUser
{
public function handle(Request $request, Closure $next, int $maxAttempts = 60, int $decayMinutes = 1)
{
$key = 'rate_limit:' . $request->user()->id;
$attempts = Cache::get($key, 0);

if ($attempts >= $maxAttempts) {
return response()->json([
'message' => 'Too many requests',
], 429);
}

Cache::put($key, $attempts + 1, now()->addMinutes($decayMinutes));

return $next($request);
}
}

6.2 日志中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class RequestLogger
{
public function handle(Request $request, Closure $next)
{
$startTime = microtime(true);

$response = $next($request);

$duration = round((microtime(true) - $startTime) * 1000, 2);

Log::channel('requests')->info('Request', [
'method' => $request->method(),
'url' => $request->fullUrl(),
'status' => $response->status(),
'duration_ms' => $duration,
'user_id' => $request->user()?->id,
]);

return $response;
}
}

6.3 CORS 中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class Cors
{
public function handle(Request $request, Closure $next)
{
$response = $next($request);

$response->headers->set('Access-Control-Allow-Origin', '*');
$response->headers->set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
$response->headers->set('Access-Control-Allow-Headers', 'Content-Type, Authorization');

return $response;
}
}

7. 最佳实践

7.1 中间件命名

1
2
3
4
5
6
7
8
9
10
// 推荐:描述性命名
CheckAge
Authenticate
VerifyCsrfToken
RateLimitRequests

// 不推荐
AgeCheck
Auth
Csrf

7.2 中间件职责

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 推荐:单一职责
class CheckAge
{
public function handle($request, Closure $next)
{
// 只检查年龄
}
}

// 不推荐:多个职责
class CheckAgeAndRole
{
public function handle($request, Closure $next)
{
// 检查年龄和角色
}
}

8. 总结

Laravel 13 的中间件新特性提供了更灵活的中间件管理:

  1. 中间件属性:声明式中间件配置
  2. 中间件参数:灵活的参数传递
  3. 中间件组:批量管理中间件
  4. 终止中间件:响应后处理

参考资料