探索 Laravel 11 的中间件
Laravel 11 于 2024 年“第一季度”发布。
我正在启动一个新项目,因为离发布日期太近了,我想我会看看新的主要版本会有什么不同。我记得 6 个月前读过 Laravel News 的一篇文章,关于 Http Kernel 是如何消失的,我对此不以为然。
当我使用 laravel new project -dev
创建项目时,我对项目规模如此之小感到非常惊讶。看到一个空的配置文件夹是非常令人惊讶的(你可以用 php artisan config:publish
发布配置文件)!
果不其然,没有 Http Kernel。那么…如何添加或更改中间件?在 Laravel 11 之前,Http Kernel(在 app/Http/Kernel.php
中)是找到中间件所有配置的地方。同样在 Laravel 11 之前,你通常不会触碰 bootstrap/app.php
。然而,在这个新版本中,情况不再如此。
老实说,作为自 v4.2
以来的 Laravel 用户,这是一个相当大的范式转变。在添加中间件之前,你需要更多的隐含知识,而不是一个易于阅读的Kernel.php
文件。
bootstrap/app.php
的新起点如下
return Application::configure()
->withProviders()
->withRouting(
web: __DIR__.'/../routes/web.php',
// api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
// channels: __DIR__.'/../routes/channels.php',
)
->withMiddleware(function (Middleware $middleware) {
//
})
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
本文只探讨中间件,不过如你所见,这是一种与我们历史上看到的截然不同的方法。我坐在那里挠头,“我如何设置自己的中间件?我如何更改默认值?”我不得不探索 Illuminate\Foundation\Configuration\middleware
类才能找到答案。
调用 Application::configure()
返回 Illuminate\Foundation\Configuration\ApplicationBuilder
实例,然后它调用各种函数 withProviders()
、withRouting()
和 withMiddleware()
函数。withMiddleware()
获取 callable
。
使用模板,我们可以通过调用 alias()
添加新的中间件别名:
function (Middleware $middleware) {
$middleware->alias([
'some_key' => \App\Http\Middleware\MyMiddleware::class,
]);
}
添加完 some_key
后,我们可以将其赋值给单独的路由或者路由组。如果我们想将中间件添加到所有请求,可以使用 append()
或 prepend()
函数添加全局中间件。
function (Middleware $middleware) {
// Using a string
$middleware->append(\App\Http\Middleware\MyMiddleware::class);
// Or adding multiple
$middleware->append([
\App\Http\Middleware\MyMiddleware::class,
\App\Http\Middleware\MyOtherMiddleware::class,
]);
}
我们可以调用 remove()
函数移除默认存在的中间件。
function (Middleware $middleware) {
// Using a string
$middleware->remove(\Illuminate\Http\Middleware\ValidatePostSize::class);
// Or removing multiple default middleware
$middleware->remove([
\Illuminate\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
]);
}
可以将中间件添加或者移除到特定的组。比如,web
组使用 appendToGroup()
/prependToGroup()
和 removeFromGroup()
函数。
function (Middleware $middleware) {
$middleware->appendToGroup('web', \App\Http\Middleware\MyMiddleware::class);
}
如果 bootstrap/app.php
开始有点乱时,我们可以将其移到可解析(invokable)的类中。
我在 app/Http
中创建了一个 AppMiddleware.php
类。如果旧习难改,你可以称之为 Kernel.php
…
<?php
namespace App\Http;
use Illuminate\Foundation\Configuration\Middleware;
class AppMiddleware
{
public function __invoke(Middleware $middleware)
{
$middleware->appendToGroup('web', \App\Http\Middleware\MyMiddleware::class);
}
}
现在在 bootstrap/app.php
中,请使用该 invokable 类的新实例替换闭包。
return Application::configure()
->withProviders()
->withRouting(
web: __DIR__.'/../routes/web.php',
// api: __DIR__.'/../routes/api.php',
commands: __DIR__.'/../routes/console.php',
// channels: __DIR__.'/../routes/channels.php',
)
->withMiddleware(new \App\Http\AppMiddleware())
->withExceptions(function (Exceptions $exceptions) {
//
})->create();
就像所有新事物一样,改变是困难的。我对这一变化有一个挥之不去的问题。我们有同样的工具和能力,但至少在一开始,要理解如何管理这一切有点困难。
我觉得这个变化需要更多关于内置中间件的隐含知识。这有关系吗?可能不会。但在某些情况下,你可能需要删除或替换默认的中间件。这需要你真正知道默认情况下有什么。不仅在全局中间件中,而且在组和别名中间件中。就我个人而言,我觉得这种变化增加了学习曲线。甚至我也忘记了默认情况下有什么或别名是什么,并定期引用 app/Http/Kernel.php
文件。
我怀疑,不冗长和文件占用空间更小是否值得?
你对这一新变化有什么想法?