如何在Python中优雅地重试发生异常的API请求

轻杰姑娘_2680

轻杰姑娘_2680

2026-09-29

451人浏览

原创

结论:优先使用 tenacity 库替代手写 while 重试——它更现代、可控,原生支持异步;手动实现易遗漏指数退避、jitter、异常筛选、边界控制等关键逻辑,且难以维护。

如何在python中优雅地重试发生异常的api请求

直接说结论:别手写 while 循环重试,用 tenacity 库——它比 retrying 更现代、更可控,且原生支持异步。

为什么不用自己写 while + try/except?

手动实现容易漏掉关键逻辑:比如指数退避(避免雪崩式重试)、 jitter(防同步风暴)、重试条件判断(不是所有异常都该重试)、最大重试次数边界控制。更麻烦的是,一旦加了日志、超时嵌套、异步支持,代码迅速变得难读难维护。

常见错误现象包括:ConnectionError 重试了但没等间隔直接冲垮下游;429 Too Many Requests 没解析 Retry-After 头就盲目重试;或者把 ValueError 这类编程错误也纳入重试,导致问题被掩盖。

实操建议:

  • 只对网络类异常(如 requests.exceptions.ConnectionError、Timeout)和明确的 HTTP 状态码(如 502、503、504)重试
  • 跳过客户端错误(4xx,除 429 外)和数据解析异常(json.JSONDecodeError)
  • 首次重试至少等待 1 秒,后续用指数退避(如 1s → 2s → 4s),并加入随机 jitter(±0.5s)

用 tenacity 重试 requests 请求(同步场景)

tenacity 的装饰器语法清晰,条件可组合,且默认不捕获所有异常——这点比很多轮子更安全。

示例:重试 3 次,仅针对连接失败、超时、以及 HTTP 5xx 响应:

from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type, retry_if_result
import requests
<p>def is_server_error(response):
return response is not None and 500 </p><p>@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=1, max=10),
retry=(
retry_if_exception_type(requests.exceptions.ConnectionError) |
retry_if_exception_type(requests.exceptions.Timeout) |
retry_if_result(is_server_error)
),
)
def fetch_data(url):
resp = requests.get(url, timeout=5)
resp.raise_for_status()  # 触发 4xx/5xx 异常
return resp.json()
</p>

注意点:

提示词大师-python版
提示词大师-python版

图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍

下载
  • wait_exponential 的 min 和 max 单位是秒,别设成毫秒(会立刻重试)
  • retry_if_result 是在函数返回后判断,适合检查响应体或状态码;而 retry_if_exception_type 是在抛异常时触发
  • 如果 API 返回 429 并带 Retry-After,得自己写一个 retry_if_result 提取 header 并动态设置等待时间(tenacity 不自动解析)

异步请求(aiohttp)怎么重试?

tenacity 原生支持 async def 函数,但必须用 @retry 装饰器 + await 调用,不能混用同步/异步装饰器。

关键差异:

  • 不能对 aiohttp.ClientSession.get() 直接装饰,要封装成独立的 async def 函数
  • 异常类型要用 aiohttp.ClientError 和 asyncio.TimeoutError
  • 重试间隔仍用 wait_exponential,但内部会自动 await asyncio.sleep()

示例片段:

import aiohttp
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
<p>@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(min=1, max=10),
retry=retry_if_exception_type((aiohttp.ClientError, asyncio.TimeoutError)),
)
async def fetch_async(url):
async with aiohttp.ClientSession() as session:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=5)) as resp:
resp.raise_for_status()
return await resp.json()
</p>

性能影响:每次重试都会新建 ClientSession(上例中),实际应复用 session。所以真实项目里,session 要作为参数传入,或通过依赖注入管理。

重试逻辑藏在哪?最容易被忽略的三个点

重试不是加个装饰器就完事。真正上线后出问题,往往卡在这几个地方:

  • 没统一处理重试日志——建议在 before 和 after 回调里打日志,记录重试次数、异常类型、当前等待秒数
  • 没隔离重试上下文——比如一次批量请求中某条失败,重试它不该影响其他请求的 timeout 计时,需确保每次重试是独立 call
  • 没考虑幂等性——GET 重试安全,但 POST/PUT 若非幂等接口,重复提交可能产生脏数据;这时重试前必须确认接口是否支持重试语义

复杂点在于:真实 API 的重试策略往往是混合的——有些要按 Retry-After 等,有些要固定间隔,有些还要降级到备用域名。这时候得用 tenacity 的 retry 组合子 + 自定义谓词,而不是硬编码一堆 if。

大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1611

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

3924

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1629

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

22577

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2767

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

2807

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1123

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

596

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2183

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程