FrankenPHP连接超时主因是Caddy或中间设备(如SLB)中断TCP长连接,非PHP代码卡住;需在Caddyfile显式配置reverse_proxy transport http { keepalive 25s }并开启debug日志排查connection closed等字段。

FrankenPHP里连接超时不是PHP代码卡住,而是底层HTTP/2或TCP连接被中间设备中断
FrankenPHP作为基于Caddy的PHP运行时,用的是长连接模型(HTTP/2 + keep-alive),但它的连接生命周期不由PHP控制,而由Caddy的HTTP服务器行为、TLS握手策略、以及上游网关(如Nginx、SLB、云防火墙)共同决定。你看到的“连接超时”,大概率不是curl或PDO在等响应,而是Caddy主动关闭了空闲连接,或者中间设备(比如阿里云SLB、腾讯云CLB)在60秒无流量后静默断开TCP,而FrankenPHP没及时感知,导致下一次复用时触发Connection reset by peer或broken pipe。
查Caddy日志和HTTP/2连接状态比看PHP错误日志更有效
FrankenPHP自身不打连接层日志,真正掌握连接生死的是它背后的Caddy。先确认Caddy是否启用了详细日志:
- 检查
Caddyfile中是否有log { level debug },没有就加上,重启 - 抓关键字段:
http.handlers.reverse_proxy.upstream.keepalive(连接池复用情况)、http.handlers.reverse_proxy.transport.http.close_idle_conns(空闲连接关闭行为) - 重点搜
connection closed、reset、idle timeout——这些不会出现在php-error.log里,但在Caddy的access/error日志里很清晰
如果用curl -v请求,留意响应头里的connection: keep-alive是否存在,以及server是否显示Caddy。若显示nginx或envoy,说明FrankenPHP前面还套了一层反向代理,那超时源头大概率在那一层。
FrankenPHP的keepalive配置必须显式设,不能依赖默认值
FrankenPHP默认不开启HTTP/2长连接复用,也不自动管理连接池。你在Caddyfile里必须手动配好两处:
立即学习“PHP免费学习笔记(深入)”;
-
reverse_proxy块内加transport http { keepalive 30s }:控制与上游PHP应用(即FrankenPHP自身)之间连接的最大空闲时间,建议设为25s,比常见SLB的60秒超时留出缓冲 -
reverse_proxy块外加header_up X-Forwarded-Proto {scheme}和header_up Connection keep-alive:确保下游能正确复用连接,否则Caddy可能把每个请求都当新连接处理 - 禁用
fastcgi相关配置——FrankenPHP走的是HTTP协议,不是FastCGI,混用会导致连接语义错乱
别信“FrankenPHP会自动适配”。它不会自动降级HTTP/2到HTTP/1.1,也不会自动重试断连;一旦连接被中间设备kill,下次请求就得重新三次握手+TLS协商,耗时直接上秒级。
PHP代码里用curl或file_get_contents访问外部服务时,超时必须独立控制
FrankenPHP进程常驻,但你的业务代码仍可能发起出站请求。这时候default_socket_timeout这种全局配置极不可靠——它会影响所有流操作,包括日志写入、临时文件读取,容易误伤。
- 对
curl:必须用curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 3000)和curl_setopt($ch, CURLOPT_TIMEOUT_MS, 8000),单位是毫秒,且要设CURLOPT_TCP_KEEPALIVE为1 - 对
file_get_contents:改用stream_context_create()构造上下文,传timeout和connect_timeout两个键,不能只设一个 - 绝对不要依赖
ini_set('default_socket_timeout', '5')——FrankenPHP启动后这个值可能被Caddy或系统覆盖,且无法区分连接超时和读超时
最易忽略的一点:FrankenPHP的worker进程不自动回收socket资源。如果你在协程或异步任务里反复new curl()却不curl_close(),连接句柄会堆积,最终触发系统级Too many open files,表现就是随机超时,查MySQL连接数或lsof -p $(pidof frankenphp)才能发现。



















