先看现象。PHP 8.2 用 curl 调流式接口,开了 CURLOPT_RETURNTRANSFER,页面白屏 40 秒后内容一次性出现,中间没有任何增量,nginx 还报了 upstream timed out。

这类报错背后常见的原因有几处,逐个排除就行。RETURNTRANSFER 会等完整响应再返回。也可能是没有设置 WRITEFUNCTION 逐块输出。

少数情况下是PHP 的输出缓冲把小块攒在一起。

不容易想到的是,fastcgi 的读超时短于生成总时长。

去掉 RETURNTRANSFER 改用回调逐块输出

php -r '$c=curl_init();curl_setopt($c,CURLOPT_WRITEFUNCTION,function($c,$d){echo $d;flush();return strlen($d);});curl_exec($c);'

接着关掉输出缓冲与压缩

php -r 'while(ob_get_level()){ob_end_flush();}echo "ok";'

随后确认 nginx 的 fastcgi_read_timeout 够长

php -r 'echo ini_get("max_execution_time");'

剩下的就是用 curl 命令行加 -N 对照服务端行为

curl -N http://localhost/stream.php

这台环境是别人交接的,不少默认值被动过,只能一项项核。

同事提醒我看一下最近一次发布,时间点确实对得上。

怎么算真的好了,看的是同一批现象。浏览器能逐段收到内容,首字节时间在 1 秒内,页面不再等到最后一次性刷新。

这里还有个坑。PHP 侧要同时处理 curl 回调、输出缓冲和 web 服务器超时三层,少一层都会表现成整包返回。同一份配置在测试环境跑通,不代表线上没事,两边的默认值经常不一样。

作者 9823189