curlopt_connecttimeout仅控制tcp连接建立超时,不包含dns解析和tls握手;curlopt_timeout则覆盖整个请求周期,含dns、连接、传输全过程。

PHP 8.1 网站接口超时不是等它卡住再猜原因,而是要分层打点:先确认是连接阶段卡死、传输中途挂起,还是应用逻辑拖慢响应;每层对应不同工具和代码级干预点,漏掉一层就可能白调半天。
第一步:确认超时发生在哪一层
用 curl 命令分离 TCP 连接、TLS 握手、首字节返回三个耗时:
curl -o /dev/null -s -w "connect: %{time_connect}s, pretransfer: %{time_pretransfer}s, starttransfer: %{time_starttransfer}s, total: %{time_total}s\n" https://your-api.com/endpoint
如果 time_connect > 3s,说明 DNS 或 TCP 建连失败,直接跳到「数据库连接超时」排查;
如果 time_pretransfer 和 time_starttransfer 差值大(比如 >5s),说明 TLS 握手或服务端路由延迟高;
【若 time_starttransfer 接近 time_total,说明 PHP 脚本本身处理慢,不是网络问题】
这一步必须在服务器本地执行,避免客户端网络干扰。
第二步:定位 PHP 应用层慢因
在接口入口加内存与时间双埋点:
复制AI写代码
1 echo "start: " . round(memory_get_usage(true) / 1024 / 1024, 2) . " MB @ " . microtime(true) . "\n";
2 // 执行业务逻辑
3 echo "after DB: " . round(memory_get_usage(true) / 1024 / 1024, 2) . " MB @ " . microtime(true) . "\n";
4 // 处理数组或渲染视图
5 echo "end: " . round(memory_get_usage(true) / 1024 / 1024, 2) . " MB @ " . microtime(true) . "\n";
观察两件事:内存是否阶梯式上涨(静态缓存无清理)、时间戳差值是否集中在某段(比如 after DB 到 end 耗时 8 秒);
若内存涨得快但没降,检查 static $cache[] 是否无上限追加;
【别依赖 unset($data),它不释放内存,只解引用;真正释放在请求结束,但若被闭包 use 或全局变量持有,GC 就收不走】
第三步:针对性优化三类高频场景
方法一:数据库连接卡住
mysqli_connect() 不支持传超时参数,必须拆成三步:
$mysqli = mysqli_init(); → mysqli_options($mysqli, MYSQLI_OPT_CONNECT_TIMEOUT, 3); → mysqli_real_connect($mysqli, $host, $user, $pass, $db, $port);
注意:MYSQLI_OPT_CONNECT_TIMEOUT 只管 TCP 连接,不管 DNS;DNS 慢就提前失败,建议生产环境直连 IP。
方法二:cURL 请求挂起
必须设毫秒级超时,且分开控制:
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 2000); → curl_setopt($ch, CURLOPT_TIMEOUT_MS, 8000); → curl_setopt($ch, CURLOPT_LOW_SPEED_LIMIT, 1); curl_setopt($ch, CURLOPT_LOW_SPEED_TIME, 10);
LOW_SPEED 防止“已连上但不动”的假活连接占满句柄。
方法三:长循环中内存不回收
遍历 10 万条记录时,每轮 new 对象又只 unset 引用,GC 不主动跑;必须手动触发:
for ($i = 0; $i
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











