public function getContents()
{
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
$contents = stream_get_contents($this->stream);
if ($contents === false) {
throw new \RuntimeException('Unable to read stream contents');
}
return $contents;
}
public function __toString()
{
try {
$this->seek(0);
return (string) stream_get_contents($this->stream);
} catch (\Exception $e) {
return '';
}
}
组件版本:
workerman/workerman v4.0.36
workerman/http-client v1.0.9
workerman/webman-framework v1.3.13
在webman中创建自定义进程,该进程只启动一个进程,进程内注册一个Timer,Timer的回调函数中使用workerman/http-client异步请求,请求成功回调中$response->getBody()->getContents()始终为空字符串,代码大致如下
public function onWorkerStart(Worker $worker)
{
$worker->count = 1;
if($this->configListeners){
// 拉取配置项文件
foreach ($this->configListeners as $listener){
list($dataId, $group, $tenant, $configPath) = $listener;
if(!file_exists($configPath)){
$this->_get($dataId, $group, $tenant, $configPath);
}
$this->timers[$dataId] = Timer::add(
$this->longPullingInterval,
function () use($dataId, $group, $tenant, $configPath){
$this->client->config->listenerAsyncUseEventLoop([
'dataId' => $dataId,
'group' => $group,
'contentMD5' => md5(file_get_contents($configPath)),
'tenant' => $tenant
], function (Response $response) use($dataId, $group, $tenant, $configPath){
if($response->getStatusCode() === 200){
if($response->getBody()->getContents() !== ''){
$this->_get($dataId, $group, $tenant, $configPath);
}
}
}, function (\Exception $exception){
Log::channel('error')->error($exception->getMessage(), $exception->getTrace());
}, $this->longPullingInterval * 1000);
});
}
}
}
public function requestAsyncUseEventLoop(string $method, string $uri, array $options = [])
{
try {
# 同步阻塞获取token
if($token = $this->issueToken()){
$options[RequestOptions::QUERY]['accessToken'] = $token;
}
$queryString = http_build_query($options[RequestOptions::QUERY] ?? []);
$headers = array_merge($options[RequestOptions::HEADERS] ?? [], [
'Connection' => 'keep-alive'
]);
$this->httpClientAsync()->request(
sprintf('http://%s:%d%s?%s', $this->host, $this->port, $uri, $queryString),
[
'method' => $method,
'version' => '1.1',
'headers' => $headers,
'data' => $options['data'] ?? [],
'success' => $options['success'] ?? function (Response $response) {},
'error' => $options['error'] ?? function (\Exception $exception) {}
]
);
} catch (RequestException $exception) {
if ($exception->hasResponse()) {
if (200 != $exception->getResponse()->getStatusCode()) {
return $this->setError(false, $exception->getResponse()->getBody()->getContents());
}
}
return $this->setError(false, 'server notice:' . $exception->getMessage());
}
}
实际上我打印了Request中onMessage的$response_data中是由body值,且不为空字符串的,如下图:
^ array:3 [
"start-line" => "HTTP/1.1 200 "
"headers" => array:7 [
"Pragma" => array:1 [
0 => "no-cache"
]
"Expires" => array:1 [
0 => "Thu, 01 Jan 1970 00:00:00 GMT"
]
"Cache-Control" => array:1 [
0 => "no-cache,no-store"
]
"Content-Type" => array:1 [
0 => "application/json;charset=UTF-8"
]
"Content-Length" => array:1 [
0 => "44"
]
"Date" => array:1 [
0 => "Thu, 12 May 2022 07:50:38 GMT"
]
"Connection" => array:1 [
0 => "close"
]
]
"body" => "config.yaml%02DEFAULT_GROUP%02fj_oh-test%01\n"
]
稍微调试了一下,感觉是Request中367行的handleData方法中的write没有把数据写入stream,因为我打印了传入的data是有值的,但是write后立马对其getContents,依然是空字符串:
我在Stream的write方法中直接对流进行操作:
很奇怪,fwrite返回了int,表示数据写入了流,但我立马stream_get_content该流,却依旧是空字符串
这里直接使用stream_get_contents($this->stream)无法获取到数据,但是stream_get_contents($this->stream,$result,0)就可以
这个问题我也出现过,但是我忘记这么解决的了。。。。
这个地方是因为打开的流没有将偏移归零,始终是在流末尾,所以按照默认参数获取的数据是空,这个时候用fseek进行归零就好了。
在workerman/http-client下用(string)$this->_response->getBody()代替$this->_response->getBody()->getContent()是解决办法,这个是一个bug,在__toString中,使用了fseek,但在getContent()中并没有,所以获取不到数据。