requests中retry不生效的主因是httpadapter未通过session.mount()显式挂载到session,且需分别挂载"http://"和"https://";status_forcelist、allowed_methods和backoff_factor配置不当也会导致重试失效。

requests 里 retry 不生效?检查 Session 和 HTTPAdapter 的绑定关系
很多人直接 new 一个 requests.Session(),再配 HTTPAdapter,但没把 adapter mount 到 session 上,retry 就完全不触发。核心是:adapter 必须显式 mount 才生效,不是“设了就自动用”。
-
Session()默认不带任何重试逻辑,哪怕你实例化了HTTPAdapter也不起作用 - 必须调用
session.mount("https://", adapter)和session.mount("http://", adapter),否则只对匹配 scheme 的请求生效 - 如果只 mount
https://,而请求的是http://地址,retry 会静默失效 - 推荐统一 mount 两个 scheme,避免因协议切换漏掉重试
重试条件太宽或太窄?重点看 status_forcelist 和 allowed_methods
默认的 Retry 对象只对连接错误、超时重试,不会对 500、429 这类状态码重试——除非你明确写进 status_forcelist。同时,allowed_methods 控制哪些 HTTP 方法允许重试,GET/HEAD 默认开启,POST/PUT 默认关闭(因为非幂等)。
- 要重试 502/503/504,必须加
status_forcelist=[502, 503, 504] - 想对 POST 也重试,得显式传
allowed_methods=["GET", "POST", "PUT", "DELETE"],但要注意语义安全 - 429(rate limit)建议加入
status_forcelist,配合Retry的backoff_factor实现退避 - 别盲目加
allowed_methods=["ALL"],requests 不识别这个字符串,会报ValueError
重试间隔不按预期?backoff_factor 不是固定秒数,而是指数退避系数
backoff_factor 看起来像“每次多等几秒”,实际是按公式 wait = backoff_factor * (2 ** (retry_number - 1)) 计算等待时间,单位是秒。第一次重试不等待,第二次等 backoff_factor 秒,第三次等 backoff_factor * 2 秒,以此类推。
- 设
backoff_factor=1,三次重试的等待分别是:0s、1s、2s、4s - 设
backoff_factor=0.3,对应等待是:0s、0.3s、0.6s、1.2s——更适合高频轻量请求 - 注意:系统时钟精度、DNS 解析耗时、网络抖动都会叠加在退避时间上,实测间隔往往比理论值略长
- 如果需要更精细控制(比如 jitter),得自己封装 retry 逻辑,原生
urllib3.Retry不支持
异步场景下用 aiohttp 或 httpx?别硬套 requests 的 retry 模式
requests 是同步阻塞库,它的 Retry + HTTPAdapter 在 asyncio 里完全不可用。强行用 loop.run_in_executor 包一层,不仅没解决并发问题,还掩盖了真正的异步重试需求。
立即学习“Python免费学习笔记(深入)”;
-
aiohttp自带ClientTimeout,但无内置 retry;需配合asyncio.sleep和手动循环,或用第三方包如aiohttp-retry -
httpx支持同步/异步双模式,其AsyncClient可用Transport层挂 retry,但配置方式和 requests 完全不同 - 别试图把 requests 的
Retry对象传给httpx.AsyncClient——类型不兼容,运行时报TypeError - 真正要并发重试,优先考虑
httpx.AsyncClient+ 自定义 transport,而不是在 asyncio 里塞 requests
重试不是加个参数就完事,关键在匹配真实失败原因:是 DNS 不稳?服务端偶发 503?还是客户端 socket 被复位?不同原因对应不同的 status_forcelist、allowed_methods 和 backoff_factor 组合。漏掉任意一环,重试就只是假装努力。










