python import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry import logging # 初始化日志配置 logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) logger = logging.getLogger("APIClient") class APIClient: def __init__(self, base_url, timeout=30, max_retries=3, backoff_factor=1.0): self.base_url = base_url.rstrip('/') self.timeout = timeout # 创建持久化Session,复用连接,提升请求效率 self.session = requests.Session() # 核心重试策略配置 retry_strategy = Retry( total=max_retries,# 最大重试总次数 backoff_factor=backoff_factor,# 指数退避因子 status_forcelist=[429, 500, 502, 503, 504],# 触发重试的错误状态码 allowed_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD"],# 支持重试的请求方法 raise_on_redirect=False, raise_on_status=False ) # 挂载重试适配器到HTTP/HTTPS请求 adapter = HTTPAdapter(max_retries=retry_strategy) self.session.mount("http://", adapter) self.session.mount("https://", adapter) def request(self, method, endpoint, **kwargs): # 拼接完整请求地址 url = f"{self.base_url}/{endpoint.lstrip('/')}" # 优先级:用户传入超时 > 默认超时 kwargs.setdefault("timeout", self.timeout) try: logger.info(f"发送 {method} 请求:{url}") response = self.session.request(method, url, **kwargs) response.raise_for_status()# 非2xx状态码主动抛异常 logger.info(f"请求成功,状态码:{response.status_code}") return response.json() except requests.exceptions.Timeout as e: logger.error(f"请求超时异常:{str(e)}") raise except requests.exceptions.ConnectionError as e: logger.error(f"网络连接异常:{str(e)}") raise except requests.exceptions.HTTPError as e: logger.error(f"HTTP请求错误:{str(e)},响应内容:{e.response.text if e.response else '无'}") raise except Exception as e: logger.error(f"未知请求异常:{str(e)}") raise # 封装常用GET请求 def get(self, endpoint, params=None, **kwargs): return self.request("GET", endpoint, params=params, **kwargs) # 封装常用POST请求 def post(self, endpoint, data=None, json=None, **kwargs): return self.request("POST", endpoint, data=data, json=json, **kwargs) # 调用示例 if __name__ == "__main__": # 初始化客户端,自定义超时、重试次数、退避因子 client = APIClient("https://api.example.com", timeout=5, max_retries=3, backoff_factor=0.5) try: result = client.get("/users/1") print("接口返回数据:", result) except Exception: logger.exception("API接口调用最终失败") |