似乎ZendFramework2的各种http客户端适配器允许在秒范围内连接和读取超时;通过在设置之前将各种超时参数强制转换为(int)来强制执行。在我们的组织中,我们通常为生产环境指定较小的连接和读取超时(我们已实施SOA)。
但是,php支持(浮点)值中的Socket级别函数可以支持超时以支持亚秒级超时,并且自PHP 5.2.3起,有一些方法可以使用libcurl支持亚秒级连接超时。 (CURLOPT_CONNECTTIMEOUT_MS,cURL符合每个how enable curl's AsynchDNS?的c-ares。)
我很高兴为ZendFramework输入一张机票,以支持更小,更精细的超时,但我想首先看看这是否是一个解决的问题,在野外'。有没有人得到Zend \ Http \ Client \ Adapter \ Socket或\ Curl适配器来支持亚秒连接和读取超时?
答案 0 :(得分:1)
我知道解决问题的两种方法。你可以使用它作为临时修复,直到Zend Framework 2支持它自己的亚秒超时。
覆盖Socket
/ Curl
类
创建模块并从Socket
/ Curl
类继承并覆盖connect()
方法以支持亚秒超时。
对于Curl
类,我会在配置数组中添加一个新选项timeout_ms
,因此您仍然可以使用旧的timeout
选项。 我的代码仅显示超时部分的相关更改。
<?php
use Zend\Http\Client\Adapter\Curl;
class CurlMs extends Curl
{
public function connect($host, $port = 80, $secure = false)
{
...
// Replace the lines with timeout with the following lines.
if (isset($this->config['timeout_ms'])) {
// Set timeout milliseconds
curl_setopt($this->curl, CURLOPT_CONNECTTIMEOUT_MS, $this->config['timeout_ms']);
} elseif (isset($this->config['timeout'])) {
// Set timeout
curl_setopt($this->curl, CURLOPT_CONNECTTIMEOUT, $this->config['timeout']);
}
...
}
}
对于Socket
类,由于stream_socket_client()
和stream_socket_timeout()
的接口不同,情况有点难以解决。选项timeout
现在是浮点值。 如上所述,我只包含了相关的代码部分。
<?php
use Zend\Http\Client\Adapter\Socket;
class SocketMs extends Socket
{
public function connectconnect($host, $port = 80, $secure = false)
{
...
// Replace the lines with socket connect
$this->socket = stream_socket_client(
$host . ':' . $port,
$errno,
$errstr,
(float) $this->config['timeout'],
$flags,
$context
);
...
// Replace the lines with stream timeout
// get the fraction of the float value and convert it microseconds
$fraction = ($this->config['timeout'] - floor($this->config['timeout'])) * 1000;
// Set the stream timeout
if (!stream_set_timeout($this->socket, (int) $this->config['timeout'], (int) $fraction) {
throw new AdapterException\RuntimeException('Unable to set the connection timeout');
}
...
}
}
修补Socket.php
/ Curl.php
个文件
为要添加亚秒超时的文件编写补丁,并将其应用于ZendFramework 2版本。如果您使用composer,则可以使用ZendFramework 2 version 2.3.3自动执行该过程。我针对{{3}}创建了补丁。
我不推荐这种方法,因为它有一些陷阱。
Curl.php
文件的补丁如下:
--- a/library/Zend/Http/Client/Adapter/Curl.php
+++ b/library/Zend/Http/Client/Adapter/Curl.php
@@ -200,7 +200,10 @@ class Curl implements HttpAdapter, StreamInterface
curl_setopt($this->curl, CURLOPT_PORT, intval($port));
}
- if (isset($this->config['timeout'])) {
+ if (isset($this->config['timeout_ms'])) {
+ // Set timeout milliseconds
+ curl_setopt($this->curl, CURLOPT_CONNECTTIMEOUT_MS, $this->config['timeout_ms']);
+ } elseif (isset($this->config['timeout'])) {
// Set timeout
curl_setopt($this->curl, CURLOPT_CONNECTTIMEOUT, $this->config['timeout']);
}
Socket.php
文件的补丁如下:
--- a/library/Zend/Http/Client/Adapter/Socket.php
+++ b/library/Zend/Http/Client/Adapter/Socket.php
@@ -247,7 +247,7 @@ class Socket implements HttpAdapter, StreamInterface
$host . ':' . $port,
$errno,
$errstr,
- (int) $this->config['timeout'],
+ (float) $this->config['timeout'],
$flags,
$context
);
@@ -268,7 +268,9 @@ class Socket implements HttpAdapter, StreamInterface
}
// Set the stream timeout
- if (!stream_set_timeout($this->socket, (int) $this->config['timeout'])) {
+ // get the fraction of the timeout and convert it to microseconds
+ $fraction = ($this->config['timeout'] - floor($this->config['timeout'])) * 1000;
+ if (!stream_set_timeout($this->socket, (int) $this->config['timeout'], (int) $fraction)) {
throw new AdapterException\RuntimeException('Unable to set the connection timeout');
}