workerman-php / workerman-php/http-client
Swoole HTTPS keep-alive 响应内容较大时,会出现最后一段数据需要在链接断开时才会触发事件回调的情况
Personne n'a encore pris cette issue.
- Langage dominant
- PHP
- Étoiles
- 55
- Forks
- 19
- Métriques de merge des PR
- Aucune PR mergée en 30 j
Description
代码如下:
$connection = $request->connection;
$client = new Client([
'max_conn_per_addr' => 128, // 每个域名最多维持多少并发连接
'keepalive_timeout' => 30, // 连接多长时间不通讯就关闭
'connect_timeout' => 5, // 连接超时时间
'timeout' => 120, // 请求发出后等待响应的超时时间
]);
$client->request('https://app.unpkg.com/vue@3.5.17/files/dist/vue.esm-browser.js', [
'method' => 'GET',
'version' => '1.1',
'headers' => ['Connection' => 'keep-alive'],
'progress' => function($buffer) use ($connection) {
$connection->send(new Chunk(time()." 响应大小: " . strlen($buffer).PHP_EOL));
},
'success' => function($response) use ($connection) {
$connection->send(new Chunk(time()." 响应成功"));
$connection->send(new Chunk('')); // 发送空的的chunk代表response结束
},
'error' => function (\Throwable $exception) use ($connection) {
$connection->send(new Chunk(time()." 响应失败: ".$exception->getMessage()));
$connection->send(new Chunk(''));
},
]);
return new Response(200, ["Transfer-Encoding" => "chunked"], '');
请求的这个 js 文件大小为 535 kB,由于开启了 keepalive,所以服务器会保持链接 60s,此时会出现能正常速度的输出很大一部分的响应大小,然后在最后一点内容的时候会一直 hang 住,直到链接被服务器关闭,才能正常的输出响应成功,或者是读取超时被 ConnectionPool 主动断开,如下所示:
....
1750845988 响应大小: 8192
1750845988 响应大小: 8192
1750845988 响应大小: 8192
1750846107 响应失败: read 104.18.0.22:443 timeout after 120 seconds
但如果将headers中的Connection设置为close,即:
'headers' => ['Connection' => 'close'],
此时再请求就会很正常的完成输出:
...
1750845798 响应大小: 8192
1750845798 响应大小: 8192
1750845798 响应大小: 7295
1750845798 响应成功
环境:
> php -v
PHP 8.2.8 (cli) (built: Jul 10 2023 23:07:42) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.8, Copyright (c) Zend Technologies
with Zend OPcache v8.2.8, Copyright (c), by Zend Technologies
> php --ri swoole
swoole
Swoole => enabled
Author => Swoole Team <team@swoole.com>
Version => 6.0.2
Built => Jun 25 2025 10:47:55
coroutine => enabled with boost asm context
epoll => enabled
eventfd => enabled
signalfd => enabled
cpu_affinity => enabled
spinlock => enabled
rwlock => enabled
sockets => enabled
openssl => OpenSSL 3.1.8 11 Feb 2025
dtls => enabled
http2 => enabled
json => enabled
curl-native => enabled
curl-version => 8.12.1
c-ares => 1.19.1
zlib => 1.2.13
brotli => E16777225/D16777225
zstd => 1.5.5
mutex_timedlock => enabled
pthread_barrier => enabled
futex => enabled
mysqlnd => enabled
io_uring => enabled
Directive => Local Value => Master Value
swoole.enable_library => On => On
swoole.enable_fiber_mock => Off => Off
swoole.enable_preemptive_scheduler => Off => Off
swoole.display_errors => On => On
swoole.use_shortname => On => On
swoole.unixsock_buffer_size => 8388608 => 8388608
根据代码追踪,可以确认是\Workerman\Events\Swoole::callRead()方法没有被触发,表现就是最后一段响应长度较小,未能出发 Swoole Event 的可读事件,导致这一部分数据一直在 buffer 中,无法被 PHP 代码读取。具体原因受限于我的知识面,无法深入了解了。
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Piste de recherche
Reproduisez la requête keep-alive en utilisant l’exemple de l’issue, puis inspectez \Workerman\Events\Swoole::callRead() et la gestion des événements Swoole autour des données de réponse mises en tampon. Comparez keep-alive avec Connection: close et ajoutez un test de régression montrant que le dernier petit fragment déclenche la progression et le succès sans attendre la fermeture de la connexion ni l’expiration du délai.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Évaluation
- Stack technique
- php
- Domaine
- networking
- Type d'issue
- Bug
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Activité
- À l'abandon
- Clarté
- Plutôt claire
- Accessibilité débutants
- 35/100