【问题标题】:How to perform an HTTP request from a Module#onBootstrap(...) in ZF2?如何从 ZF2 中的 Module#onBootstrap(...) 执行 HTTP 请求?
【发布时间】:2023-03-05 11:44:01
【问题描述】:

在 Zend Framework 2 应用程序的 Module 类中,我向特殊端点发送 HTTP 请求以获取有关用户的一些信息。当我在工厂内执行此操作时(如下代码中的第一种方法),它可以工作。它也适用于Module#onBootstrap(...) 中的侦听器定义(即第二种方法)。但是,当我尝试直接从Module#onBootstrap(...)(s. 3d 方法)执行调用时,调用失败并出现错误:

PHP Fatal error: Uncaught exception 'Zend\\Http\\Client\\Adapter\\Exception\\TimeoutException' with message 'Read timed out after 30 seconds' in /var/www/path/to/project/vendor/zendframework/zend-http/src/Client/Adapter/Socket.php:600
Stack trace:
#0 /var/www/path/to/project/vendor/zendframework/zend-http/src/Client/Adapter/Socket.php(412): Zend\\Http\\Client\\Adapter\\Socket->_checkSocketReadTimeout()
#1 /var/www/path/to/project/vendor/zendframework/zend-http/src/Client.php(1389): Zend\\Http\\Client\\Adapter\\Socket->read()
#2 /var/www/path/to/project/vendor/zendframework/zend-http/src/Client.php(893): Zend\\Http\\Client->doRequest(Object(Zend\\Uri\\Http), 'POST', false, Array, '')
#3 /var/www/path/to/project/module/MyApi/src/MyApi/Module.php(158): Zend\\Http\\Client->send()
#4 /var/www/path/to/project/module/MyApi/src/MyApi/Module.php(33): MyApi\\Module->retrieveUserInfosEndpoint(Object(ZF\\ContentNegotiation\\Request), 'http://my-project...')
#5 [intern in /var/www/path/to/project/vendor/zendframework/zend-http/src/Client/Adapter/Socket.php on line 600

为什么会出现错误?如何从 Module#onBootstrap(...) 发送 HTTP 请求?


namespace MyModule;
...
class Module
{
    protected $userInfo;
    public function onBootstrap(MvcEvent $mvcEvent)
    {
        // 3d approach -- it does NOT work
        $userInfoEndpointUrl = $serviceManager->get('Config')['user_info_endpoint_url'];
        $request = $serviceManager->get('Request');
        $this->userInfo = $this->retrieveUserInfosEndpoint($request, $userInfoEndpointUrl);
        ...
        $halPlugin->getEventManager()->attach('myeventname', function ($event) use (..., $serviceManager) {
            // 2nd approach -- it works
            $userInfoEndpointUrl = $serviceManager->get('Config')['user_info_endpoint_url'];
            $request = $serviceManager->get('Request');
            $this->userInfo = $this->retrieveUserInfosEndpoint($request, $userInfoEndpointUrl);
            /*
            PHP Fatal error:
            Uncaught exception 'Zend\\Http\\Client\\Adapter\\Exception\\TimeoutException'
            with message 'Read timed out after 30 seconds'
            in /var/www/path/to/project/vendor/zendframework/zend-http/src/Client/Adapter/Socket.php:600
            */
            ...

        });
        ...
    }
    ...
    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                'MyModule\\V1\\Rest\\Foo\\FooService' => function(ServiceManager $serviceManager) {
                    // 1st approach -- it works
                    $userInfoEndpointUrl = $serviceManager->get('Config')['user_info_endpoint_url'];
                    $request = $serviceManager->get('Request');
                    $this->userInfo = $this->retrieveUserInfosEndpoint($request, $userInfoEndpointUrl);
                    ...
                    return $fooService;
                },
                ...
            ),
            ...
        );
    }

    private function retrieveUserInfosEndpoint($request, $userInfoEndpointUrl)
    {
        $authorizationHeaderValue = $request->getHeader('Authorization')->getFieldValue();
        $client = new Client();
        $client->setUri($userInfoEndpointUrl);
        $client->setMethod('POST');
        $client->setOptions(['sslverifypeer' => false]);
        $client->setHeaders(['Authorization' => $authorizationHeaderValue]);
        $client->setOptions([
            'maxredirects' => 10,
            'timeout'      => 30,
        ]);
        $client->setParameterPost([]);
        $response = $client->send();
        $userInfo = json_decode($response->getContent(), true);
        return $userInfo;
    }

}

【问题讨论】:

    标签: zend-framework2 httprequest zend-http-client


    【解决方案1】:

    嗯,我现在明白了——它实际上是行不通的。执行新请求会递归启动整个事件链并导致无限循环。

    在我的情况下,为了避免多次请求我的userinfo 端点,我将调用放入一个工厂,并且可以在其他工厂以及事件侦听器中使用它:

    namespace MyModule;
    ...
    class Module
    {
        public function onBootstrap(MvcEvent $mvcEvent)
        {
            ...
            $halPlugin->getEventManager()->attach('myeventname', function ($event) use (..., $serviceManager) {
                ...
                $userInfo = $serviceManager->get('MyModule\\Service\\UserInfo');
                ...
    
            });
            ...
        }
        ...
        public function getServiceConfig()
        {
            return array(
                'factories' => array(
                    'MyModule\\V1\\Rest\\Foo\\FooService' => function(ServiceManager $serviceManager) {
                        ...
                        $userInfo = $serviceManager->get('MyModule\\Service\\UserInfo');
                        ...
                        return $fooService;
                    },
                    'MyModule\\Service\\UserInfo' => function(ServiceManager $serviceManager) {
                        $userInfoEndpointUrl = $serviceManager->get('Config')['user_info_endpoint_url'];
                        $request = $serviceManager->get('Request');
                        $userInfo = $this->retrieveUserInfosEndpoint($request, $userInfoEndpointUrl);
                        return $userInfo;
                    },
                    ...
                ),
                ...
            );
        }
    }
    

    【讨论】:

    • 只需将整个逻辑留在工厂中,然后在引导方法中调用该工厂。像$userlogic->init() 这样的东西最好,因为在每个请求中都会调用整个 Module.php。
    • 感谢您的评论!但它不起作用(已经尝试过)。再一次:问题是无限循环,这是由从obBootstrap 发送的新 HTTP 请求引起的。所以,搬到工厂——是的,直接在obBootstrap 方法体中调用——不。
    猜你喜欢
    • 1970-01-01
    • 2018-06-02
    • 2011-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-07
    相关资源
    最近更新 更多