timeout不生效是因为默认为none(无限等待),且单数值timeout=5仅等价于(timeout=(5,5),无法区分连接与读取阶段;必须显式设为元组如(3,7)并捕获timeout及connectionerror异常。

requests.get() 为什么 timeout 不生效
很多人写 requests.get(url, timeout=5) 后发现程序卡住十几秒才报错,其实是没理解 timeout 的默认行为:它只控制连接建立(connect)和响应读取(read)两个阶段的总时长,但若服务器已建立连接却迟迟不发数据(比如卡在中间代理、后端 hang 住),timeout 可能被绕过。更关键的是,**不显式传参时 timeout 默认为 None(无限等待)**,不是“没设置就等于不超时”,而是“不设就永远等”。
- 必须显式传
timeout,且推荐用 tuple 形式:timeout=(3, 7)—— 前者是 connect 超时,后者是 read 超时 - 单数值如
timeout=5等价于timeout=(5, 5),但 connect 和 read 需求常不同,分开设更合理 - 如果只关心整体耗时,用
timeout=5即可;但线上服务建议拆开,避免 connect 快但 read 慢时误判
捕获 Timeout 异常的正确写法
requests.exceptions.Timeout 是 requests.exceptions.RequestException 的子类,但不能只用 except Exception: 模糊兜底——那样会吞掉真正该抛出的错误(比如 JSON 解析失败)。必须精确捕获。
常见错误写法:except requests.exceptions.Timeout: → 这行本身没错,但漏了 requests.exceptions.ConnectionError(比如 DNS 失败、拒绝连接),它和 timeout 是平级异常,不是父子关系。
- 生产环境建议统一捕获
requests.exceptions.RequestException,再按需细分处理 - 若只想处理超时,必须同时考虑
Timeout和底层的socket.timeout(某些低版本 urllib3 会抛这个) - 示例片段:
import requests
from requests.exceptions import Timeout, RequestException
try:
resp = requests.get("https://httpbin.org/delay/10", timeout=(2, 5))
resp.raise_for_status()
except Timeout:
print("请求超时:连接或响应读取超时")
except RequestException as e:
print(f"其他请求异常:{e}")
timeout 设置太小会导致什么问题
设成 timeout=(0.1, 0.1) 看似“严格”,实际会让大量正常请求失败——DNS 解析、TCP 握手、TLS 协商都可能耗时超过 100ms,尤其跨公网或首次访问域名时。这不是代码 bug,是网络现实。
- 局域网内 API 调用:connect 可设 0.5–1s,read 视业务逻辑定(如计算型接口可 2–5s)
- 公网第三方服务(如微信、支付宝):connect 至少 3s,read 建议 8–15s,它们后端链路长,偶尔抖动正常
- 不要全局设死值,应按 endpoint 分级配置,比如用字典存不同服务的 timeout 策略
- 超时后重试要谨慎:HTTP GET 可重试,POST/PUT 建议加幂等 key,否则重复提交
如何验证 timeout 是否真的起作用
靠等 10 秒看是否报错不可靠。要用可控的延迟服务测试,比如 https://httpbin.org/delay/{n},它会精确挂起 n 秒后返回。
- 测试 connect 超时:用一个根本不存在的域名,如
requests.get("http://this-domain-does-not-exist.test", timeout=(0.5, 5)),0.5s 内应抛ConnectionError - 测试 read 超时:用
https://httpbin.org/delay/6+timeout=(3, 5),5s 后应触发Timeout - 注意:本地 hosts 绑定或 DNS 缓存可能干扰 connect 测试,建议先
ping或nslookup确认解析行为
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











