connect_timeout控制TCP连接及TLS握手超时,read_timeout控制单次recv响应体的阻塞等待时长;需用httpx.Timeout(connect=, read=)实例设置,不可用字典或浮点数。

httpx 中 connect_timeout 和 read_timeout 的作用区别
在 httpx 里,connect_timeout 控制的是建立 TCP 连接(含 TLS 握手)的最长等待时间;read_timeout 控制的是从服务器收到响应头之后,读取响应体(body)的单次阻塞等待时长(注意:不是整个响应体读完的总耗时)。两者不叠加,也不互斥,各自独立生效。
如何分别设置 connect_timeout 和 read_timeout
直接通过 timeout 参数传入 httpx.Timeout 实例即可,不能用字典或浮点数。常见错误是传 timeout=10 或 timeout={"connect": 3, "read": 5} —— 这些写法要么触发默认全局 timeout,要么抛 TypeError。
正确做法:
import httpxtimeout = httpx.Timeout( connect=3.0, # 建连超时 read=8.0, # 单次读响应体超时 write=None, # 通常不需要设写超时,留 None 即可 pool=None # 连接池等待超时,一般也留 None )
client = httpx.Client(timeout=timeout) response = client.get("https://www.php.cn/link/26bc286a7c996dc103ada0982493576e")
read_timeout 不等于 “整个响应读取完成” 的超时
这是最容易误解的一点:read_timeout 是每次调用底层 socket recv() 的超时,不是整个响应 body 读完的总时限。如果服务端分块发送大文件,而每块间隔小于 read_timeout,请求仍可能成功;反之,哪怕只卡在某一次 recv 上超过该值,就会抛 httpx.ReadTimeout。
- 要限制整体响应耗时,得靠
httpx.Timeout(timeout=total)(即统一 timeout),但这样会同时约束 connect + read + write - 若需精细控制,只能自己封装逻辑:用流式响应(
stream=True)+ 手动计时 + 分块读取 + 主动中断 -
read_timeout设太小(如 0.1)容易在高延迟网络或慢速服务端上误触发,尤其对 chunked transfer 编码响应
异步客户端中 timeout 设置方式完全一致
异步用 httpx.AsyncClient 时,timeout 参数签名和行为与同步客户端完全一样,没有额外适配成本。
示例:
import httpxtimeout = httpx.Timeout(connect=2.0, read=6.0) async with httpx.AsyncClient(timeout=timeout) as client: response = await client.get("https://www.php.cn/link/4d2fe2e8601f7a8018594d98f28706f2")
注意:不要试图在 get() 调用时再传 timeout=... —— 那只会覆盖 client 级别的 timeout,且无法单独指定 connect/read,只能传 float 或 Timeout 实例。
真正复杂的地方在于:当服务端响应头已返回、但响应体迟迟不发全时,read_timeout 只管“下一次 recv”,不保你一定能拿到完整 body;这时候得结合业务逻辑判断是否重试、截断或告警。










