【问题标题】:Why does a container run before middleware?为什么容器在中间件之前运行?
【发布时间】:2020-05-02 02:12:54
【问题描述】:

如果我们看一下在 slim4 website 和其他地方发布的中间件概念。

它应该在请求到达应用程序之前或向用户发送响应时执行。

问题是这样的,因为即使之前执行了一个中间件,应用程序也会调用一个容器:

给我看代码。

配置

'providers' => [,
    App\ServiceProviders\Flash::class => 'http'
],
'middleware' => [
    App\Middleware\Session::class => 'http,console',
],

会话中间件

class Session
{
    public function __invoke(Request $request, RequestHandler $handler)
    {
        if (session_status() !== PHP_SESSION_ACTIVE) {

            $settings = app()->getConfig('settings.session');

            if (!is_dir($settings['filesPath'])) {
                mkdir($settings['filesPath'], 0777, true);
            }

            $current = session_get_cookie_params();
            $lifetime = (int)($settings['lifetime'] ?: $current['lifetime']);
            $path = $settings['path'] ?: $current['path'];
            $domain = $settings['domain'] ?: $current['domain'];
            $secure = (bool)$settings['secure'];
            $httponly = (bool)$settings['httponly'];

            session_save_path($settings['filesPath']);
            session_set_cookie_params($lifetime, $path, $domain, $secure, $httponly);
            session_name($settings['name']);
            session_cache_limiter($settings['cache_limiter']);
            session_start();
        }

        return $handler->handle($request);
    }
}

Flash 消息容器

class Flash implements ProviderInterface
{

    public static function register()
    {
        $flash = new Messages();
        return app()->getContainer()->set(Messages::class, $flash);
    }
}

执行应用

...
 // Instantiate PHP-DI ContainerBuilder
    $containerBuilder = new ContainerBuilder();
    AppFactory::setContainer($containerBuilder->build());
    $app = AppFactory::create();


    $providers = (array)$this->getConfig('providers');
    array_walk($providers, function ($appName, $provider) {
        if (strpos($appName, $this->appType) !== false) {
            /** @var $provider ProviderInterface */
            $provider::register();
        }
    });



    $middlewares = array_reverse((array)$this->getConfig('middleware'));
    array_walk($middlewares, function ($appType, $middleware) {
        if (strpos($appType, $this->appType) !== false) {
            $this->app->add(new $middleware);
        }
    });


.... 

$app->run();

结果

`Fatal error: Uncaught RuntimeException: Flash messages middleware failed. Session not found.` 

我知道Flash消息需要一个会话开始工作,中间件应该负责这样做,但它总是在容器之后执行

【问题讨论】:

  • 当将多个中间件添加到应用程序(或路由)时,它们会形成一个堆栈,这意味着您添加的最后一个是第一个执行的。因此,您需要确保将负责启动新会话的会话中间件添加为最后一个中间件。
  • 这个我很理解,碰巧这个项目只有一个中间件,1个中间件和4个容器(依赖)我正在为slim 4写一个新的骨架。你想看看仓库,看看你能不能帮忙?
  • 当然,我会看一下,但如果您包含问题中包含的所有必需信息,那就太好了。我看到您在添加中间件后尝试向容器添加依赖项。这似乎是您的代码的问题。在执行其他代码部分(依赖于它们)之前,应该已经定义了依赖关系。
  • 这是存储库。如果您能帮我解开这个结,我将不胜感激。 github.com/jerfeson/slim4-skeleton
  • 请在您的问题中添加所有相关详细信息 - 外部资源随时可能发生变化,并且对将来遇到该问题的人没有用处。特别是,添加您的中间件序列以及您如何配置这些容器。添加有关正在注册的中间件和依赖项以及按什么顺序进行的调试信息也很有用。应该避免让人们通过 git 存储库挖掘相关信息。

标签: php containers middleware slim-4


【解决方案1】:

首先,您使用 dependencycontainer 术语,就好像它们是同一个东西,但它们不是。

关于您的代码问题,在Flash::register() 方法中,您正在从Messages 类创建一个新对象,并将其放入 DI 容器中。您正在调用此方法并强制创建 Message 对象,该对象需要已经启动会话,之前让中间件启动会话。您确实应该避免将对象存储在 DIC 中,而不是存储它们的定义(它们是如何构建的)。我的意思是以下更改:

class Flash implements ProviderInterface
{
    public static function register()
    {
        return app()->getContainer()->set(Messages::class, function() {
            return new Messages();
        });
    }
}

【讨论】:

  • 谢谢你,太棒了。
猜你喜欢
  • 1970-01-01
  • 2021-01-29
  • 1970-01-01
  • 1970-01-01
  • 2022-07-07
  • 1970-01-01
  • 2023-02-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多