在使用 Python 的 requests 库时,有时可能会遇到网络不稳定、连接中断等问题,因此实现重连机制是很有必要的。requests库本身没有直接提供重试机制,但可以结合 urllib3Retry类以及requests.adapters.HTTPAdapter来实现。

Retry 类(urllib3.util.retry.Retry)

Retry类是 urllib3 库中的一个工具,用于设置请求的重试逻辑。它允许你指定请求失败时的重试次数、哪些错误类型触发重试、以及重试的时间间隔等参数。Retry类可以用于实现强大的网络请求容错机制。

常用参数:

  • total: 重试的总次数。设为 None 或 0 表示不重试。
  • read: 读取失败时的重试次数。
  • connect: 连接失败时的重试次数。
  • backoff_factor: 用于控制重试间隔时间的因子。第一次重试间隔时间为 backoff_factor,第二次重试的时间间隔为 backoff_factor * 2^1,第三次为 backoff_factor * 2^2,依此类推(指数退避算法)。
  • status_forcelist: 一个状态码列表,当请求返回这些 HTTP 状态码时触发重试(例如 500、502、503 等服务器错误)。
  • allowed_methods: 指定哪些 HTTP 方法允许重试(如 GET、POST)。默认情况下,仅对幂等方法(如 GET、PUT、DELETE)执行重试。
  • raise_on_redirect: 如果设为 True,超过重定向次数后会抛出 MaxRetryError。
  • raise_on_status: 如果设为 True,超过状态码触发次数后会抛出 MaxRetryError。

Retry 的使用示例:

from urllib3.util.retry import Retry

retry_strategy = Retry(
    total=3,  # 总共重试3次
    status_forcelist=[500, 502, 503, 504],  # 这些状态码将触发重试
    method_whitelist=["HEAD", "GET", "OPTIONS"],  # 允许重试的方法
    backoff_factor=1  # 重试时间间隔为1秒,逐次递增
)

HTTPAdapter 类 (requests.adapters.HTTPAdapter)

HTTPAdapter是 requests 库中的一个适配器,用来管理底层 HTTP 连接的参数和行为,包括连接池、重试逻辑、以及如何对 HTTP 请求进行传输等。

默认情况下,requests 使用的是标准的HTTPAdapter,它不具备重试功能。但是,我们可以通过自定义 HTTPAdapter并将其与Retry类结合来实现重试机制。

常用参数:

  • max_retries: 设置重试策略,这个参数可以直接传递一个 Retry 对象。
  • pool_connections: 连接池的最大连接数,默认是 10。可以减少重复的 TCP 握手时间,提升性能。
  • pool_maxsize: 连接池中最大连接数,超过时请求会阻塞等待空闲连接。
  • pool_block: 如果连接池已满,是否阻塞等待。默认是 False,表示超出连接池后抛出异常。

HTTPAdapter 的使用示例:

from requests.adapters import HTTPAdapter

adapter = HTTPAdapter(max_retries=retry_strategy)
session = requests.Session()
session.mount("http://", adapter)
session.mount("https://", adapter)

实现重连

通过将Retry实例作为HTTPAdapter的参数,你可以将请求重试策略添加到你的 HTTP 会话中。

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

# 定义重试策略
retry_strategy = Retry(
    total=3,  # 重试总次数
    status_forcelist=[500, 502, 503, 504],  # 针对哪些状态码重试
    backoff_factor=1  # 重试间隔时间的因子,逐次递增
)

# 创建 HTTPAdapter 并设置重试策略
adapter = HTTPAdapter(max_retries=retry_strategy)

# 创建一个 requests session,并挂载适配器
session = requests.Session()
session.mount("http://", adapter)
session.mount("https://", adapter)

# 发起请求
response = session.get('http://example.com',timeout=5)
print(response.status_code)