Http::timeout() 设置的是接收响应超时,即请求发出后等待完整响应的最长时间,不包括DNS解析和连接建立等前置耗时,最终透传给Guzzle的timeout选项。

Http::timeout() 设置的是什么超时
Http::timeout() 控制的是 HTTP 客户端发起请求后,等待响应的最长时间(单位:秒),不包括 DNS 解析、连接建立等前置耗时。它最终会透传给底层 Guzzle 的 timeout 选项,属于「接收响应超时」(curl_setopt($ch, CURLOPT_TIMEOUT_MS, ...) 的变体)。这个值只影响单次请求,不会改变 PHP 脚本整体执行时间。
为什么设了 timeout 还是报 ConnectionException
常见错误现象:Illuminate\Http\Client\ConnectionException 报 “cURL error 28: Operation timed out” —— 这说明请求连响应头都没收到,已触发底层 cURL 的总超时。此时你设的 Http::timeout(5) 是生效的,但可能被其他因素覆盖:
- PHP 的
max_execution_time小于你的timeout值,脚本先被 PHP 中断 - FPM 的
request_terminate_timeout更短,Nginx 的fastcgi_read_timeout也未同步调大,网关提前断连 - 目标服务本身响应极慢或网络链路不稳定,5 秒确实不够
解决办法:优先确认 Http::timeout() 是否真被调用(检查代码路径是否走到了该行),再逐层排查网关和 PHP 层限制。
如何配合 retry() 实现更稳的外部调用
单纯加 timeout 只是“等更久”,真正提升可用性得靠重试 + 状态判断:
- 用
Http::retry(3, 100)表示最多重试 3 次,每次间隔 100 毫秒;失败时抛出ConnectionException或 5xx 异常 - 必须搭配
timeout()使用,否则默认无超时,重试可能卡死 - 对 4xx 错误(如 401、404)通常不该重试,要用
$response->clientError()单独处理 - 示例:
Http::timeout(8)->retry(2, 200)->get('https://api.example.com/data')
别忽略底层连接池与 keep-alive 影响
HTTP 客户端默认复用连接(keep-alive),但若目标服务主动关闭空闲连接,下次复用时可能触发隐式超时。这不是 timeout() 能控制的,而是 connect_timeout 和 http_errors 的责任范围:
- 需要显式设置连接建立阶段超时,得用
Http::withOptions(['connect_timeout' => 3]) - 如果不想让 4xx/5xx 自动转异常,保持
'http_errors' => false(默认就是 false) - 长周期高频调用建议启用连接池(Laravel 10+ 支持,9.x 需手动配 Guzzle HandlerStack)
真正容易被忽略的是:timeout 和 connect_timeout 是两个独立参数,一个管“连上了等多久”,一个管“连不上等多久”,漏掉后者,DNS 故障或服务宕机时照样卡住。


















