在使用 Python 的 requests
库时,有时可能会遇到网络不稳定、连接中断等问题,因此实现重连机制是很有必要的。requests
库本身没有直接提供重试机制,但可以结合 urllib3
的Retry
类以及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)