Python进阶:从requests请求重试到万能重试装饰器

点击上方 “ AI派 ”, 选择“ 设为星标
最新分享,第一时间送达!

640?wx_fmt=jpeg


作者:郑明卓,Python研发工程师,在Python开发与爬虫方面涉猎较广,拥抱新技术。目前负责应用技术调研与开发维护。Now is better than never。

编辑:王老湿

在前面我们介绍了Python进阶的一个应用:功能测试。具体文章见:

从requests请求重试到万能重试装饰器

重试,在编写代码的过程中,是一个很常见的需求。

  1. 请求重试(例如:超时)

  2. 文件占用

  3. IO阻塞等待

那么,我们如何编写重试的代码呢?

主要涉及内容:

  • requests adapter

  • 函数装饰器

  • 类装饰器

话不多说,start!

因为我们需要从 requests 请求重试开始,为了方便测试请求,我们用 flask 编写一个简单的服务器,用于请求测试。

准备请求服务器

服务器的功能比较简单,用来查看请求次数和观察是否重试成功,flask_server.py代码如下:

from time import sleep

from flask import Flask, jsonify, Response

app: Flask = Flask(__name__)

retry_count: int = 0  # 用于重试请求的计数


@app.route("/api/retry", methods=["GET"])
def retry_api() -> Response:
    """
    延时 1s 的请求接口, 响应时间 > 1s。
    :return:
    """
    global retry_count
    retry_count += 1
    print(f"这是第{retry_count}次请求")
    if retry_count < 3:
        sleep(1)
    else:
        retry_count = 0  # 计数清零
    return jsonify({"msg": "已经三次了哦!"})


if __name__ == '__main__':
    app.run()

代码比较简单,由于没有找到好用的flask上下文来完成计数需求,这里为了简单操作,就直接应用了全局变量来计数(仅用于测试,未加锁),而没有使用redis数据库来计数了。

编写好之后,我们运行代码即可。这样,我们用来测试重试的服务器就准备好了。

接下来,我们先来看看一般的 requests 超时请求如何实现。

1.`requests` 请求重试(常见版本)

我们用 try...except... 语句捕捉timeout错误。进行循环重试即可。我们编写一个函数 get_datanormal.py代码如下:

from typing import Dict, Any

import requests

BaseDictData = Dict[str, Any]


def get_data(url: str, max_retry: int = 0, time_out: float = 3., **kwargs) -> BaseDictData:
    """自动重试 timeout 错误 的方法"""
    params: BaseDictData = kwargs.get("params", {})  # 不管你传了什么奇怪的东西, 我只收这个
    headers: BaseDictData = kwargs.get("headers", {})  # 同上
    for i in range(max_retry + 1):
        """进行最大重试次数的遍历"""
        try:
            response: requests.Response = requests.get(
                url=url,
                params=params,
                headers=headers,
                timeout=time_out,
            )
        except requests.ReadTimeout:
            print(f"第{i + 1}次请求失败,正在重试。")
        else:
            return response.json()  # 没有错误,直接返回

    print(f"{max_retry + 1} 次请求都失败了,返回空值,便于后续逻辑处理。。。")
    return {}


if __name__ == '__main__':
    print(get_data("http://localhost:5000/api/retry", max_retry=1, time_out=.01))

在该函数中,我们利用 requests 库本身的 timeout 参数进行错误捕捉。整体比较简单,设计逻辑即:

640?wx_fmt=png

如果超时,那么就会引发错误,然后继续请求,用for循环来处理循环重试,更加简洁。

超过最大次数,就返回空数据,成功,返回成功数据。

代码段注意要点:try...except... 语句

try:
    ...  # 需要捕捉异常的代码
except xxx:
    ...  # 发生异常处理逻辑
else:
    ...  # 如果 try 成功执行,就执行else,否则跳过else
finally:
    ...  # 一定会执行该语句块

我们在 try 语句块中只运行了一行代码,因为这次捕捉只针对这行代码可能会引起的错误

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值