如何设置 Laravel 中间件的执行顺序?

Posted

技术标签:

【中文标题】如何设置 Laravel 中间件的执行顺序?【英文标题】:How to set the Laravel middleware order of execution? 【发布时间】:2015-09-12 23:31:21 【问题描述】:

Laravel 5 documentation 描述了两种分配中间件的方法:

    将中间件分配给控制器的路由。 在控制器的构造函数中指定中间件。

然而,我意识到任何写在控制器 __construct() 函数中的代码都会在 Middleware 之前运行,即使 Middleware 是在第一行声明的控制器的__construct 函数。

我在 Laravel github 存储库中找到了一个 bug report 来解决类似的问题。然而,一位合作者关闭了该问题,并指出“这是预期的行为。”。

我认为middleware 应该是应用程序之外的“层”,而__construct 函数是应用程序的一部分。

为什么__construct 函数在中间件之前执行(假设它是在中间件运行之前声明的)?为什么会出现这种情况?

【问题讨论】:

我只是做了一些测试来确认。如果您希望中间件在您的控制器__construct() 之前执行,您需要将中间件分配给路由。否则它将始终在__construct() 的末尾执行,即使分配在construct() 的第一行。 我创建了一个快速示例来概述您所描述的内容,请随时将其添加到您的问题中。 notehub.org/2015/6/26/say-we-have-a-controller----welcomecontr @Jeemusu 感谢您的评论。是的,我还发现了两种分配中间件的方式之间的差异。但是,通过将中间件放在构造函数中执行流程的末尾,是否违反了请求生命周期(laravel.com/docs/5.1/lifecycle),因为调度请求应该在末尾? 【参考方案1】:

另一个回答该问题的另一个用例

如果它与中间件之间的顺序有关

您可以在 App\Kernel 中更新 $middlewarePriority。

【讨论】:

这应该被接受,这样我就可以命令中间件的执行 Laravel 5: laravel.com/docs/5.8/middleware#sorting-middleware ; Laravel 8(当前):laravel.com/docs/8.x/middleware#sorting-middleware【参考方案2】:

应用程序逻辑驻留在控制器的方法中。所以基本上应用程序存在于控制器的方法中,而不是整个控制器本身。

中间件在请求进入相应的控制器方法之前运行。因此,这总是在真正的应用程序之外。除非所有中间件都传递请求,否则不会执行任何控制器方法。

您放入控制器构造函数中的$this->middleware("My\Middleware"); 语句注册My\Middleware 用于在请求进入应用程序之前进行检查。

如果您看到中间件的代码并且 如果请求通过,那么我们使用$next($request); 语句将其发送到下一个中​​间件。这允许为单个请求执行多个中间件。现在,如果 Laravel 在 $this->middleware(...); 语句处运行中间件,Laravel 可能无法知道接下来应该检查哪个中间件。

所以,Laravel 解决了这个问题,首先注册所有的中间件,然后将请求一个一个地传递给所有的中间件。

【讨论】:

一个有趣的例子,中间件相对于构造函数运行。任何全局中间件实际上似乎在构造函数之前运行,而任何本地中间件在构造函数之后运行。这种不一致在过去给我带来了困惑和麻烦。 所以首先运行的原因是我不清楚答案我希望它遵循 group route => route specified (按数组顺序) 然后 controler construct 。这是真的吗 我仍然对 laravel 如何决定运行它们的顺序感到困惑。它是按字母顺序排列的吗? 现在在 5.7 中,甚至全局中间件也在控制器构造之后运行!【参考方案3】:

App\Http\Kernel中设置中间件优先级

例如,在这里我需要我的自定义身份验证中间件首先运行(在替换绑定之前),所以我将它移到堆栈上:

public function __construct(Application $app, Router $router)

    /**
     * Because we are using a custom authentication middleware,
     * we want to ensure it's executed early in the stack.
     */
    array_unshift($this->middlewarePriority, MyCustomApiAuthMiddleware::class);

    parent::__construct($app, $router);

或者,如果您需要显式控制,您可以覆盖整个优先级结构(不推荐,因为您必须在升级过程中密切注意以查看框架是否发生变化)。针对此问题的是处理路由模型绑定的 SubstituteBindings 类,因此请确保您的身份验证中间件在此之前的某个时间出现。

/**
 * The priority-sorted list of middleware.
 *
 * Forces the listed middleware to always be in the given order.
 *
 * @var array
 */
protected $middlewarePriority = [
    \App\Http\Middleware\MyCustomApiAuthMiddleware::class
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \Illuminate\Auth\Middleware\Authenticate::class,
    \Illuminate\Session\Middleware\AuthenticateSession::class,
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    \Illuminate\Auth\Middleware\Authorize::class,
];

【讨论】:

【参考方案4】:

他们更新了middlewarescontroller 和控制器构造之间的执行顺序。

以前是:

1. The global middleware pipeline
2. The route middleware pipeline
3. The controller middleware pipeline

现在是:

1. The global middleware pipeline
2. Controller's Construct
3. The route & controller middlewares

在这里阅读更多: https://laracasts.com/discuss/channels/general-discussion/execution-order-in-controllers-constructor-whit-middleware https://laravel-news.com/controller-construct-session-changes-in-laravel-5-3

【讨论】:

以上是关于如何设置 Laravel 中间件的执行顺序?的主要内容,如果未能解决你的问题,请参考以下文章

大白话 Laravel 中间件

通过中间件方法访问Laravel会话 - 会话存储未根据请求设置

再见,顺序执行!异步RPC还得靠消息队列中间件!

进程管理顺序执行和并发执行

laravel 怎么设置数据库端口

第46篇 多线程如何排队执行