requests.get()超时需设为元组timeout=(connect, read),单值timeout=5等价于(5,5);DNS解析计入connect阶段;responses无法模拟超时或连接异常,应patch Session.request或用不可达地址触发。

requests.get() 超时参数怎么设才真正生效
超时没起作用,大概率是因为只设了 timeout 但没分清连接超时和读取超时。requests 的 timeout 是个“双参数元组”,不是单个数字。
-
timeout=(3, 10)表示:3 秒内必须完成 TCP 连接,之后最多再等 10 秒接收响应体;前者是connect timeout,后者是read timeout - 只写
timeout=5等价于timeout=(5, 5),看似简单,但实际中连接快、读取慢更常见,硬绑死容易误判 - 如果传
timeout=None或完全不传,读取阶段会无限等待(比如服务器卡住但没断连),这是线上服务最危险的配置 - 注意:DNS 解析耗时算在 connect 阶段里,若 DNS 不稳,
connect timeout会先触发
用 responses 库模拟 requests.Timeout 异常
responses 默认不抛超时异常,它只是拦截并返回预设响应。要测超时逻辑,得绕过它的正常流程,用 mock 强制触发。
- 别用
responses.add()想“配出一个超时”,它做不到;responses本质是 HTTP 响应拦截器,不是网络栈模拟器 - 正确做法是用
unittest.mock.patch替换requests.adapters.HTTPAdapter.send,在里面手动 raiserequests.exceptions.Timeout - 或者更轻量:patch
requests.Session.request,对特定 URL 返回异常,避免侵入底层 adapter - 示例片段:
with mock.patch("requests.Session.request") as mock_req: mock_req.side_effect = requests.exceptions.Timeout("mocked timeout") try: requests.get("https://api.example.com/data") except requests.exceptions.Timeout: pass # 此处验证你的重试/降级逻辑
为什么用 responses.add() 拦截后,ConnectionError 还是不出现
responses.add() 成功拦截时,根本不会走真实网络层,所以 ConnectionError、ConnectTimeout 这类底层异常压根不会抛出——它们发生在 socket 连接阶段,而 responses 在更高层劫持了请求。
- 想测
ConnectionError,必须让请求真正发出并失败,比如关掉目标服务、改错 host、或用mock.patch拦截 socket 层(不推荐,太重) - 更实用的替代方案:用本地不可达地址,如
requests.get("http://127.0.0.1:9999", timeout=0.1),配合短 timeout 触发ConnectionRefusedError - 注意:某些系统(尤其 macOS)对 localhost 的连接失败响应较快,Linux 可能稍慢,测试时 timeout 值要留余量
- 如果你依赖
responses做大部分 mock,又需要覆盖连接失败路径,建议把这两类 case 拆开——用 responses 测业务逻辑,用真实失败地址测异常分支
超时测试里最容易被忽略的细节
很多人写了 timeout 测试,却在线上发现行为不一致,问题往往出在环境差异和异常类型混淆上。
立即学习“Python免费学习笔记(深入)”;
- Python 版本影响:3.11+ 对 timeout 的底层处理更严格,老版本可能静默延长;确保测试环境 Python 小版本和生产一致
- 不要只 assert “是否抛异常”,还要检查异常类型是否精确匹配——
requests.exceptions.Timeout和requests.exceptions.ConnectTimeout是不同子类,业务逻辑可能区分处理 - HTTP/2 或代理场景下,timeout 行为可能变化:比如使用
httpx或带 proxy 的 requests,connect 阶段会多一次代理握手,超时需额外预留 - mock 时 patch 错对象很常见:比如 patch 了
requests.get却忘了模块里实际调的是session.get(),结果测试永远走不到异常分支










