🎤 Laravel 中间件讲座:依赖注入与条件分支策略的奇妙之旅
大家好!欢迎来到今天的 Laravel 技术讲座 🎉。今天我们要聊的是中间件(Middleware)这个 Laravel 的核心概念,特别是它的 依赖注入 和 条件分支策略。如果你觉得这些听起来很复杂,别担心!我会用轻松诙谐的语言和代码示例带你一步步理解。
🛠️ 什么是中间件?
在 Laravel 中,中间件就像一个“守门人”,它可以在 HTTP 请求到达控制器之前或之后执行一些操作。比如:
- 验证用户是否登录
- 检查用户是否有权限访问某个资源
- 记录请求日志
- 压缩响应数据
简单来说,中间件就是一个函数,接收输入并返回输出,同时可以对输入或输出进行处理。
🔍 中间件依赖注入
1. 什么是依赖注入?
依赖注入(Dependency Injection, DI)是现代 PHP 开发中非常重要的设计模式。它的核心思想是:不要自己创建对象,而是让外部将对象传递进来。
在 Laravel 中,中间件可以通过构造函数或方法参数实现依赖注入。下面我们通过代码来感受一下。
2. 构造函数中的依赖注入
假设我们有一个 AuthMiddleware
,需要使用 Auth
服务来验证用户是否登录。我们可以这样写:
namespace AppHttpMiddleware;
use Closure;
use IlluminateSupportFacadesAuth;
class AuthMiddleware
{
protected $auth;
public function __construct(Auth $auth)
{
$this->auth = $auth; // 通过构造函数注入 Auth 服务
}
public function handle($request, Closure $next)
{
if (!$this->auth->check()) {
return redirect('login'); // 如果未登录,重定向到登录页面
}
return $next($request); // 继续处理请求
}
}
💡 注意:Laravel 的服务容器会自动解析 Auth
对象,并将其传递给中间件的构造函数。这就是依赖注入的魅力!
3. 方法参数中的依赖注入
有时候,你可能不需要在整个中间件生命周期内都使用某个依赖,而只是在 handle
方法中用到一次。这时,你可以直接在方法参数中进行依赖注入:
public function handle($request, Closure $next, IlluminateContractsAuthGuard $auth)
{
if (!$auth->check()) {
return redirect('login');
}
return $next($request);
}
虽然这种方式也可以工作,但通常推荐在构造函数中注入依赖,因为它更清晰、更符合 SOLID 原则。
🌳 条件分支策略:让中间件更有智慧
有时候,我们希望中间件只在特定条件下执行。例如,只有当用户来自移动端时才应用某种逻辑。这种需求可以通过条件分支策略来实现。
1. 使用 Closure
参数动态传递条件
Laravel 允许我们在注册中间件时动态传递参数。例如:
Route::middleware(['auth:admin'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});
在这个例子中,auth:admin
表示我们传递了一个参数 admin
给 AuthMiddleware
。那么如何在中间件中接收这个参数呢?
public function handle($request, Closure $next, $guard = null)
{
if ($guard === 'admin' && !$this->auth->guard($guard)->check()) {
return redirect('login');
}
return $next($request);
}
在这里,$guard
是从路由定义中传递过来的参数。如果 $guard
等于 'admin'
,我们就使用 admin
守卫来验证用户。
2. 根据请求条件动态执行
除了通过参数控制中间件行为,我们还可以根据请求的上下文动态决定是否执行某些逻辑。例如,检查用户是否来自移动端:
public function handle($request, Closure $next)
{
if ($request->header('User-Agent') && str_contains($request->header('User-Agent'), 'Mobile')) {
// 如果是移动端请求,执行特定逻辑
return response('This is a mobile request.');
}
return $next($request);
}
📊 总结对比表
为了让大家更清楚地理解中间件依赖注入和条件分支策略的区别,我做了一个简单的对比表:
特性 | 依赖注入 | 条件分支策略 |
---|---|---|
作用 | 注入外部服务或对象 | 根据条件动态调整中间件的行为 |
实现方式 | 构造函数或方法参数 | 路由参数或请求上下文 |
适用场景 | 需要长期使用的外部服务 | 需要根据条件动态调整逻辑 |
代码示例 | public function __construct(Auth $auth) |
if ($request->header('User-Agent')) {} |
🚀 实战演练
为了让内容更加生动,我们来做一个小练习。假设我们需要实现一个中间件,用于限制 API 请求的频率。要求如下:
- 如果用户没有登录,则不限制。
- 如果用户已登录,则每分钟最多允许 60 次请求。
下面是实现代码:
namespace AppHttpMiddleware;
use Closure;
use IlluminateSupportFacadesAuth;
use IlluminateSupportFacadesCache;
class ApiThrottleMiddleware
{
public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1)
{
if (!Auth::check()) {
return $next($request); // 如果未登录,不限制
}
$key = 'api_throttle_' . Auth::id();
$attempts = Cache::increment($key);
if ($attempts === 1) {
Cache::put($key, 0, now()->addMinutes($decayMinutes));
}
if ($attempts > $maxAttempts) {
return response()->json(['error' => 'Too many requests'], 429);
}
return $next($request);
}
}
💡 提示:这里的 Cache
服务也是通过依赖注入的方式引入的,但为了简化代码,我们直接使用了 Facade。
🎉 结语
好了,今天的讲座就到这里啦!我们学习了 Laravel 中间件的依赖注入和条件分支策略。通过这些技术,你可以让中间件变得更灵活、更强大。
如果你觉得这篇文章有用,请给我点个赞 👏,或者在评论区告诉我你的想法 😊。下次见!