walkor / walkor/workerman

Swoole6.2.1 事件循环下 HTTPS 请求超时:stream_socket_enable_crypto() 返回 false

Open
#1,161 7 comments 0 reactions 0 assignees View on GitHub
Dominant language
PHP
Stars
11.6k
Forks
2.2k
Avg merge
11h 30m
Merged PRs (30d)
3

Description

## 问题描述

在 Swoole 事件循环下,使用 `Workerman\Http\Client` 发起 HTTPS 请求时,连接卡在 `CONNECTING` 状态 30 秒后超时。

## 环境信息

| 项目 | 版本 |
|------|------|
| Workerman | 最新版 |
| Swoole | 6.2.1 |
| PHP | 8.3+ |
| 框架 | webman |
| 运行环境 | Docker |

## 复现代码

```php
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`(需要重试)的情况:

```php
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 环境下触发兼容问题 |

## 建议修复方向

1. **短期**:在文档中说明 Swoole 事件循环下 HTTPS 的兼容性问题,建议用户使用 `Swoole\Coroutine\Http\Client`
2. **长期**:考虑在 Swoole 事件循环下自动切换使用 Swoole 原生 HTTP 客户端

## 当前绕过方案

在应用层,HTTPS 请求改用 `Swoole\Coroutine\Http\Client`:

```php
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`。

Contributor guide

No contributing guide indexed for this repository

Research direction

The reported entry point is TcpConnection::doSslHandshake, with the failure occurring under Swoole's stream hook in the Docker reproduction. Start by reproducing the HTTPS request with Swoole 6.2.1 and compare the handling with commit 1391112a61d23020e11e7b89f17050f6cfaea431. The issue names no repository file or test; done requires an agreed scope and verification that the timeout is addressed or the incompatibility is documented.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, php
Domain
backend, networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.