如何在ZF2中从Module#onBootstrap(...)执行HTTP请求?

时间:2015-08-18 17:59:52

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

在Zend Framework 2应用程序的Module类中,我向特殊端点发送HTTP请求以获取有关用户的一些信息。当我在工厂内执行此操作时(s。下面的代码中的第一种方法),它可以工作。它也适用于Module#onBootstrap(...)(s。第二种方法)中的侦听器定义。但是当我尝试直接从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;
    }

}

1 个答案:

答案 0 :(得分: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;
                },
                ...
            ),
            ...
        );
    }
}