requests请求超时尝试重连的3种方式

参考文档

https://urllib3.readthedocs.io/en/latest/reference/urllib3.util.html#module-urllib3.util.retry
https://blog.csdn.net/shengruxiahua2571/article/details/103165315/

了解

连接超时 ==> 发起请求连接到建立连接之间的最大时长
读取超时 ==> 连接成功开始到服务器返回响应之间等待的最大时长

代码示例

import traceback
import time
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
retries = Retry(total=3,
                        backoff_factor=0.1,
                        status_forcelist=[ 500, 502, 503, 504 ])
s = requests.Session()
s.mount('http://', HTTPAdapter(max_retries=retries))
s.mount('https://', HTTPAdapter(max_retries=retries))
count = 0
while True:
    if count < 3:
        try:
            file = s.get(url, stream=True, timeout=5)
            return file.content
        except:
            print('Retry!')
            time.sleep(3)
            traceback.print_exc()
            count += 1
            continue
    else:
        print('Fail!')
        break
    
# 相关Retry参数说明
total  允许的重试次数
connect 要重试的连接相关错误数
read  读取错误时重试多少次
redirect  要执行的重定向数
status_forcelist 一组我们应该强制重试的HTTP状态代码
backoff_factor 在第二次尝试后在尝试之间应用的退避因素(大多数错误会立即通过第二次尝试解决,没有延迟)
raise_on_redirect  如果重定向次数用尽,是否引发 MaxRetryError 或返回响应代码在 3xx 范围内的响应。
raise_on_status  类似于raise_on_redirect:如果状态在status_forcelist范围内并且重试已经用尽,我们是否应该引发异常或返回响应。

结合项目需求使用的两种方法

方法一,普通循环请求判断

    def connection_demo(self, request):
        start_time = datetime.now()
        while True:
            ...  # 省略其它代码部分
                num_times = 0
                session = requests.Session()   # 推荐使用session可以提高访问速度
                while num_times < 3:
                    try:
                        result = session.get(url=url, verify=False, timeout=5)
                        if result.status_code == 200:
                            break
                    except requests.exceptions.RequestException:  # 如果HTTP请求返回了不成功的状态码, Response.raise_for_status() 会抛出一个 HTTPError 异常
                        num_times += 1
                        continue
                if num_times < 3:
                    break
                else:
                    raise VtuneTimeOutException
            ...  # 省略其它代码部分
        return redirect_url

方法二,requests的retry

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

def connection_demo(self, request):
    start_time = datetime.now()
    while True:
       ... # 省略其余代码部分
            req = requests.Session()
            retries = Retry(total=3,
                            backoff_factor=0.1,
                            status_forcelist=[500, 502, 503, 504])
            req.mount('https://', HTTPAdapter(max_retries=retries))
            try:
                result = req.get(url=url, verify=False, timeout=5)
                if result.status_code == 200:
                    break
                else:
                    raise VtuneTimeOutException
            except requests.exceptions.RequestException:
                raise VtuneTimeOutException
        ... # 省略其余代码部分
    return redirect_url

方法3,装饰器retry

pip install retry
自行百度

总结

需求是:后端视图代码请求由内部生成并存储到数据库中的一个url,看是否通再将url返回给前端,3次重连,根据requests的status_code为200来判断是否成功,
状态码200成功则结束,其它状态码不成功则继续,
并且在3次重连内,有超时等问题都不希望让其抛出错误,等3次重连结束后,再判断是否都不成功再抛出错误。使用第二种方法有点小bug,
具体还是要结合项目,之前没有加status_forcelist这个玩意,导致有一次请求得到503,页面报错了,但是因为有三次重连的机制,
报错了还继续执行成功了。所以后面加了status_forcelist,但是还有异常捕获的问题,因为只要有一次超时或其它问题,
都会被捕获抛异常,那样也会遇到报错了还继续执行成功了的问题。
所以我使用了第一种方式写法,当然了还是要结合项目需求来。
posted @ 2021-12-21 18:16  我在路上回头看  阅读(2517)  评论(0编辑  收藏  举报