问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

你不知道的Requests进阶技巧:用Retry实现完美重试

创作时间:
作者:
@小白创作中心

你不知道的Requests进阶技巧:用Retry实现完美重试

引用
CSDN
1.
https://blog.csdn.net/u013586693/article/details/142695026

在使用Python的Requests库进行HTTP请求时,遇到网络不稳定或服务器响应异常的情况,合理的重试机制可以提高请求的成功率。本文将详细介绍Requests库中Retry类的使用方法,帮助开发者实现更灵活和精细的重试策略。

在上一篇文章中,我们使用了HTTPAdapter中的max_retries参数对超时类的原因进行了重试。本篇文章中,我们将使用Retry类对重试的原因和过程进行精细化控制。

import logging
import requests
from requests.adapters import HTTPAdapter

# 开启 urllib3 的日志,方便查看重试过程
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
urllib3_logger = logging.getLogger('urllib3')
urllib3_logger.setLevel(logging.DEBUG)

http_adapter = HTTPAdapter(max_retries=3)
# 使用 session 发送请求
session = requests.session()
# 打印 adapters
print(session.adapters)
session.mount('https://', http_adapter)
session.mount('http://', http_adapter)
try:
    print(session.get('https://www.baidu.com', timeout=0.01).text[:100])
except Exception as e:
    print(e)
    print(type(e))

以上为之前的代码进行了一些小修改,在初始化HTTPAdapter时,传入了max_retries参数,意思是在网络超时的时候重试三次。那如果不超时只是服务器返回了不正常的响应,应该如何进行更加方便的重试呢?

查看HTTPAdapter类的初始化代码可以发现,max_retries参数最终会被赋值为Retry的实例,并且将我们的参数传入。那么如果我们想控制重试的时机以及过程,只需要传入一个自定义的Retry类就好了。


来看一下Retry的文档

Retry类参数详解

  1. total
  • 功能:控制总的重试次数。如果设置为None,则禁用总重试次数。
  • 默认值10
  • 说明:这是总的重试次数,无论错误原因是什么。包括连接失败、超时等。
  1. connect
  • 功能:针对连接错误(如DNS解析错误、TCP连接失败等)重试的次数。
  • 默认值None
  • 说明:如果为None,则使用total的值。
  1. read
  • 功能:控制在读取数据时(比如在连接成功后但在获取响应时出错)重试的次数。
  • 默认值None
  • 说明:如果为None,则使用total的值。
  1. redirect
  • 功能:重定向时允许的最大次数。
  • 默认值None
  • 说明:如果为None,默认使用total的值。设置为0禁止重定向。
  1. status
  • 功能:针对特定HTTP响应状态码(例如500、502、503、504)重试的次数。
  • 默认值None
  • 说明:如果为None,使用total的值。
  1. method_whitelist
  • 功能:一个允许重试的HTTP方法的列表。
  • 默认值frozenset(['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'])
  • 说明:如果HTTP方法不在此列表中,则不进行重试。
  1. status_forcelist
  • 功能:定义需要强制重试的HTTP状态码列表。
  • 默认值None
  • 说明:如果服务器返回此列表中的状态码,则强制重试。
  1. backoff_factor
  • 功能:控制重试之间的等待时间,等待时间的增长因子(用于指数回退)。
  • 默认值0
  • 说明:重试间隔时间为backoff_factor * (2 ** (retry次数 - 1))
  1. raise_on_redirect
  • 功能:如果设置为True,在重定向时抛出MaxRetryError
  • 默认值True
  • 说明:用于控制是否在重定向次数超过限制时抛出异常。
  1. raise_on_status
  • 功能:如果设置为True,当重试次数超过最大值且遇到特定状态码时抛出异常。
  • 默认值False
  • 说明:当遇到status_forcelist中的状态码并超出重试次数时,抛出异常。
  1. history
  • 功能:保存历史重试请求的列表,包含过去的所有重试信息。
  • 默认值None
  • 说明:可以跟踪重试的历史记录。
  1. respect_retry_after_header
  • 功能:是否尊重服务器返回的Retry-After头信息。
  • 默认值True
  • 说明:如果服务器在响应中返回Retry-After头部,设置True时将等待指定的时间后再进行重试。
  1. remove_headers_on_redirect
  • 功能:在重定向时移除的HTTP头信息列表。
  • 默认值frozenset(['Authorization'])
  • 说明:重定向时可以选择移除敏感的头部信息,如Authorization
  1. method_whitelist / allowed_methods(新的版本中使用allowed_methods
  • 功能:允许重试的HTTP方法。
  • 默认值frozenset(['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'])
  • 说明:控制哪些HTTP请求方法允许进行重试。
  1. retry_on_exception
  • 功能:自定义逻辑,指定哪些异常可以触发重试。
  • 默认值None
  • 说明:接受一个回调函数,返回True则重试。
  1. retry_on_status
  • 功能:自定义逻辑,指定哪些HTTP状态码可以触发重试。
  • 默认值None
  • 说明:接受一个回调函数,返回True则重试。

实战示例

以下示例演示了如何应用自定义的重试策略来处理特定的HTTP状态码。

import logging
import requests
from requests.adapters import HTTPAdapter
from urllib3 import Retry

# 开启 urllib3 的日志,方便查看重试过程
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
urllib3_logger = logging.getLogger('urllib3')
urllib3_logger.setLevel(logging.DEBUG)

retry_strategy = Retry(
    total=5,  # 总共重试 5 次
    connect=3,  # 连接错误时重试 3 次
    read=2,  # 读取错误时重试 2 次
    redirect=3,  # 重定向时最多重试 3 次
    status_forcelist=[500, 502, 503, 504],  # 对于这些 HTTP 状态码强制重试
    backoff_factor=1,  # 等待时间因子:指数递增,如 1s, 2s, 4s...
    raise_on_status=False  # 达到最大重试次数后不抛异常
)
http_adapter = HTTPAdapter(max_retries=retry_strategy)
# 使用 session 发送请求
session = requests.session()
# 打印 adapters
print(session.adapters)
session.mount('https://', http_adapter)
session.mount('http://', http_adapter)
# 发送请求
try:
    response = session.get("https://httpbin.org/status/500")  # 故意发送到一个会返回 500 错误的 URL
    print(response.status_code)
except requests.exceptions.RetryError as e:
    print(f"达到最大重试次数,重试失败: {e}")
except requests.exceptions.RequestException as e:
    print(f"请求失败: {e}")

在上面的代码中,定义了一个自定义的Retry类,当我们访问https://httpbin.org/status/500(它返回500错误状态码),请求会自动按照指定策略进行重试,并打印重试过程中的日志,运行结果为:

查看运行结果,总共请求了6次,其中5次是由于状态码500进行的重试,每次重试的间隔时间按设定的因子指数增长。并且每次重试后,总重试次数都在减少,最终减少到0。

大家可以按照自己的需求来初始化Retry类,可以更加方便的进行重试。如果以上参数都不能满足要求,可以使用retry_on_statusretry_on_exception在发生指定异常或者指定状态码时执行自定义函数,可以更加灵活的实现重试逻辑。

在实际开发中,利用Requests库的Retry类可以灵活应对非网络问题的重试需求。大家可以根据项目的具体情况,自定义重试参数。

retry_strategy = Retry(
    # 自行定义参数,默认不重试
)
http_adapter = HTTPAdapter(max_retries=retry_strategy)
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号