问题描述
在 Swoole 事件循环下,使用 Workerman\Http\Client 发起 HTTPS 请求时,连接卡在 CONNECTING 状态 30 秒后超时。
环境信息
| 项目 |
版本 |
| Workerman |
最新版 |
| Swoole |
6.2.1 |
| PHP |
8.3+ |
| 框架 |
webman |
| 运行环境 |
Docker |
复现代码
use Workerman\Http\Client;
$client = new Client(['timeout' => 10]);
$client->request('https://reply.lsmir2.com/reply.php', [
'method' => 'POST',
'data' => json_encode(['test' => true]),
'success' => function($response) {
echo $response->getBody()->getContents();
},
'error' => function($e) {
echo "Error: " . $e->getMessage();
},
]);
复现结果
- 期望:HTTPS 请求成功,返回响应内容
- 实际:连接卡在
CONNECTING 状态,30 秒后超时
诊断日志
[HTTP-Client][process] state before send=CONNECTING
[HTTP-Client][process] request sent
--- 30 秒后 ---
[AsyncTcp][checkConnection] called
[Swoole][callWrite] TRIGGERED! fd=244
[AsyncTcp][checkConnection] stream_socket_get_name='198.18.1.91:443'
[TcpConnection][doSslHandshake] stream_socket_enable_crypto returned=false
Swoole 内部 SSL 错误(Docker 日志):
ssl_connect(fd=12) failed. Error: error:0A0003E7:SSL routines::invalid session id
与官方修复的对比
官方 commit 1391112a61d23020e11e7b89f17050f6cfaea431 处理了返回 0(需要重试)的情况:
if ($this->sslHandshakeCompleted === 0) {
$this->eventLoop->onReadable($this->socket, $this->checkConnection(...));
$this->eventLoop->onWritable($this->socket, $this->checkConnection(...));
return;
}
但当前问题返回 false(彻底失败),官方修复未覆盖此场景。
根因分析
| 层面 |
问题 |
| Swoole |
SWOOLE_HOOK_STREAM_FUNCTION 对异步 socket SSL 握手实现有 bug,返回 invalid session id |
| Workerman |
使用标准 PHP stream API,在 Swoole hook 环境下触发兼容问题 |
建议修复方向
- 短期:在文档中说明 Swoole 事件循环下 HTTPS 的兼容性问题,建议用户使用
Swoole\Coroutine\Http\Client
- 长期:考虑在 Swoole 事件循环下自动切换使用 Swoole 原生 HTTP 客户端
当前绕过方案
在应用层,HTTPS 请求改用 Swoole\Coroutine\Http\Client:
use Swoole\Coroutine\Http\Client as SwooleHttpClient;
$client = new SwooleHttpClient($host, 443, true);
$client->setHeaders($this->headers);
$client->post($path, $data);
return new \Workerman\Http\Response($client->statusCode, $client->headers, $client->body);
验证通过:HTTPS 请求正常返回 success。
问题描述
在 Swoole 事件循环下,使用
Workerman\Http\Client发起 HTTPS 请求时,连接卡在CONNECTING状态 30 秒后超时。环境信息
复现代码
复现结果
CONNECTING状态,30 秒后超时诊断日志
Swoole 内部 SSL 错误(Docker 日志):
与官方修复的对比
官方 commit
1391112a61d23020e11e7b89f17050f6cfaea431处理了返回0(需要重试)的情况:但当前问题返回
false(彻底失败),官方修复未覆盖此场景。根因分析
SWOOLE_HOOK_STREAM_FUNCTION对异步 socket SSL 握手实现有 bug,返回invalid session id建议修复方向
Swoole\Coroutine\Http\Client当前绕过方案
在应用层,HTTPS 请求改用
Swoole\Coroutine\Http\Client:验证通过:HTTPS 请求正常返回
success。