编程

探索 Laravel 11 的中间件

1451 2024-02-06 02:03:00

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 文件。

我怀疑,不冗长和文件占用空间更小是否值得?

你对这一新变化有什么想法?