requests重试未生效主因是@retry未作用于抛异常的函数,须显式raise异常、避免吞异常、设合理重试策略并校验响应内容。

requests请求失败后重试没生效?检查retrying的装饰器用法
retrying库本身不直接拦截requests异常,必须确保@retry装饰器作用在真正抛出异常的函数上,而不是只包了一层没做错误处理的封装。常见错误是把requests.get()写在函数内部但没加raise,导致retry机制根本收不到异常信号。
实操建议:
- 被装饰的函数必须显式抛出异常(如
raise requests.RequestException),不能只返回None或空响应 - 避免在装饰函数里用
try...except吞掉异常,否则retry无法感知失败 - 若用
session.get(),记得传入timeout参数,否则网络卡住时会无限等待,retry也救不了
重试次数和间隔怎么设才合理?别盲目堆高max_attempt_number
默认max_attempt_number=5对多数HTTP错误够用,但盲目调高反而可能加重目标服务器压力,甚至触发风控。关键是区分错误类型:连接超时、DNS失败值得重试;404、403、429这类状态码重试无意义,应提前拦截。
实操建议:
- 用
retry_on_exception参数指定只重试requests.exceptions.ConnectionError和Timeout,跳过HTTPError - 配合
wait_exponential_multiplier(单位毫秒)实现指数退避,比如从100ms开始,每次×2,避免瞬间重连洪峰 - 加上
stop_max_delay=10000限制总重试耗时,防止单个请求卡死整个爬虫流程
retrying和requests.adapters.Retry冲突吗?优先用哪个?
两者不冲突,但功能重叠。requests内置的Retry更轻量、原生支持重定向和状态码控制;retrying更灵活,能套在任意函数上。实际项目中建议优先用requests.adapters.Retry配HTTPAdapter,它对连接池、SSL握手等底层失败更敏感。
实操建议:
- 初始化session时挂载带重试策略的adapter:
session.mount('https://', HTTPAdapter(max_retries=Retry(...))) - retrying留给业务逻辑层使用,比如解析JSON失败、字段缺失时重取整页,而非网络层问题
- 不要同时对同一请求既用
Retry又套@retry,容易造成重复重试、时间叠加失控
重试成功了但数据还是错的?检查response内容有效性再交出结果
retrying只管“请求发出去且没报异常”,不管返回的HTML是不是403页面、JSON是不是空对象、状态码是不是200但body含"error":true。很多稳定性问题其实出在“假成功”上。
实操建议:
- 在重试函数末尾加校验逻辑,比如
if response.status_code != 200: raise ValueError(f"HTTP {response.status_code}") - 对关键字段做存在性断言:
if not response.json().get('data'):就raise - 用
stop_max_attempt_number配合自定义retry_on_result回调,让retrying也能基于返回值判断是否继续
重试不是万能胶水,真正的稳定性来自分层防御:网络层用adapter重试,业务层用retrying兜底,每层都带精准的失败识别和退出条件。漏掉任何一层,都可能让重试变成无效循环。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











