为何Requests的Session.get()超时抛出ConnectionError而非Timeout异常?
为什么requests的GET请求超时抛出ConnectionError而非Timeout?
这个问题其实和你使用的requests版本直接相关,让我给你拆解清楚来龙去脉:
1. requests中两种超时场景的差异
requests的timeout参数实际管控两类超时情况:
- 连接超时:客户端尝试与服务器建立TCP连接时的超时(比如服务器地址不可达、拒绝连接),这类超时在几乎所有requests版本里都会抛出
requests.exceptions.Timeout。 - 读取超时:TCP连接已经成功建立,但服务器迟迟没有返回响应数据的超时(也就是你回溯里看到的
Read timed out),这个行为在不同requests版本里有明显区别:- 在requests < 2.21.0的旧版本中,读取超时会被包装成
ConnectionError抛出; - 在requests >= 2.21.0的新版本中,读取超时会抛出
requests.exceptions.ReadTimeout(它是Timeout的子类),这就和官方文档描述的行为完全一致了。
- 在requests < 2.21.0的旧版本中,读取超时会被包装成
你的错误日志明确显示是Read timed out,说明是读取阶段的超时,而你当前使用的requests版本刚好是旧版,所以才会抛出ConnectionError而非预期的Timeout。
2. 可行的解决方案
针对这个问题,你有两种处理思路:
方案一:升级requests版本
直接升级到最新稳定版,就能让读取超时抛出Timeout类异常,和文档行为对齐:
pip install --upgrade requests
方案二:兼容旧版本的异常捕获
如果因为环境限制无法升级,你可以同时捕获Timeout和ConnectionError,并通过异常信息判断是否属于读取超时:
from requests.exceptions import Timeout, ConnectionError with requests.Session() as rs: try: with rs.get(url, params={}, headers={}, auth=self.auth, verify=self.ssl_verify, timeout=30) as r: # 处理响应逻辑 pass except Timeout: # 处理连接超时场景 print("建立连接时超时") except ConnectionError as e: if "Read timed out" in str(e): # 处理读取超时场景 print("等待响应时读取超时") else: # 处理其他连接错误(比如DNS解析失败、连接被拒绝等) print(f"发生连接错误:{e}")
额外补充:你可以把timeout参数拆成元组,分别设置连接超时和读取超时,比如timeout=(5, 30),表示5秒内必须建立连接,30秒内必须拿到响应数据,这样能更精准地管控不同阶段的超时情况。
内容的提问来源于stack exchange,提问作者Shuzheng
相关产品推荐
相关产品推荐

