Python requests如何对status_code=200但error非零的响应触发重试
解决方案
方案1:自定义继承urllib3的Retry类(推荐,可复用urllib3原生重试逻辑)
urllib3的Retry类支持重写响应可重试判断逻辑,你可以继承该类重写is_response_retryable方法,在方法内解析响应体的error字段判断是否需要重试,示例代码如下:
import json from urllib3 import Retry class CustomRetry(Retry): def is_response_retryable(self, response): # 可保留原生状态码判断逻辑,不需要也可以删除 if super().is_response_retryable(response): return True # 解析响应体判断error字段 try: data = json.loads(response.data) return data.get("error", 0) != 0 except (json.JSONDecodeError, AttributeError): # 响应不是合法JSON的场景可按需设置是否重试 return True
之后将自定义的CustomRetry实例传给urllib3的PoolManager即可,其余重试参数(重试次数、间隔、允许重试的方法白名单等)和原生Retry的用法完全一致。
方案2:外层封装独立重试逻辑
如果不想修改urllib3的内置重试逻辑,也可以在请求外层自行封装重试判断,适配性更高,可灵活控制重试触发条件、间隔、回调逻辑等,以下是用通用重试库tenacity实现的示例:
import json import urllib3 from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_result http = urllib3.PoolManager() def is_api_failed(response): """判断接口是否返回失败需要重试""" try: data = json.loads(response.data) return data.get("error", 0) != 0 except Exception: return True # 重试配置:最多重试3次,指数退避间隔,接口返回失败则触发重试 @retry( stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=1, max=10), retry=retry_if_result(is_api_failed) ) def send_request(method, url, **kwargs): resp = http.request(method, url, **kwargs) return resp
注意事项
- 解析响应体前建议先判断响应的Content-Type是否为JSON,避免不必要的解码错误
- 非幂等请求(比如POST提交数据)的重试要谨慎,避免重复提交导致业务异常,可以限制仅GET、HEAD等幂等方法重试
- 如果响应体较大,多次读取可能产生性能损耗,可以按需添加仅小体积响应才解析body判断的逻辑
内容的提问来源于stack exchange,提问作者caverac
相关产品推荐
相关产品推荐

