• 作者:老汪软件技巧
  • 发表时间:2024-10-04 21:00
  • 浏览量:

 class="hljs language-python" lang="python">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 的文档

1. total2. connect3. read4. redirect5. status6. method_whitelist7. status_forcelist8. backoff_factor9. raise_on_redirect10. raise_on_status11. history12. respect_retry_after_header13. remove_headers_on_redirect14. method_whitelist / allowed_methods (新的版本中使用 allowed_methods)15. retry_on_exception16. retry_on_status实战

以下示例演示了如何应用自定义的重试策略来处理特定的 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 类,当我们访问 (它返回 500 错误状态码),请求会自动按照指定策略进行重试,并打印重试过程中的日志,运行结果为:

查看运行结果,总共请求了 6 次,其中 5 次是由于状态码 500 进行的重试,每次重试的间隔时间按设定的因子指数增长。

并且每次重试后,总重试次数都在减少,最终减少到 0。

大家可以按照自己的需求来初始化 Retry 类,可以更加方便的进行重试。

如果以上参数都不能满足要求,可以使用 retry_on_status 或 retry_on_exception 在发生指定异常或者指定状态码时执行自定义函数,可以更加灵活的实现重试逻辑。

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

retry_strategy = Retry(
    # 自行定义参数,默认不重试
)
http_adapter = HTTPAdapter(max_retries=retry_strategy)