【干货满满】如何处理requests库调用API接口时的异常情况

在使用requests库调用 API 接口时,异常情况(如网络波动、服务器错误、参数错误等)难以避免。若不妥善处理,可能导致程序崩溃或数据丢失。以下是系统化的异常处理方案,涵盖常见异常类型、处理策略、实战代码最佳实践,确保接口调用稳定可靠。

一、requests 库常见异常类型

requests库的异常主要分为两类:HTTP 错误状态码 (如 404、500)和网络 / 连接异常(如超时、连接失败)。具体分类如下:

异常类型 触发场景 示例
HTTP 错误 服务器返回错误状态码(4xx 客户端错误、5xx 服务端错误) 401(未授权)、404(接口不存在)、500(服务器内部错误)
连接异常 网络中断、域名解析失败、目标服务器不可达 无网络时调用接口、URL 域名错误(如https://xxx.invalid
超时异常 连接或读取数据超过设定时间未完成 接口响应过慢(如 10 秒未返回)、服务器负载过高
请求 URL / 参数异常 URL 格式错误、参数类型不匹配 URL 含特殊字符未编码、POST 请求体格式错误(非 JSON)
其他未知异常 不可预见的错误(如库本身 bug、系统资源不足) 内存溢出导致请求中断

二、异常处理的核心策略

针对不同异常类型,需设计差异化处理逻辑,核心原则是:明确错误原因→针对性恢复→避免程序崩溃

1. HTTP 错误:解析状态码,明确错误类型

服务器返回的状态码(response.status_code)是定位问题的关键,需根据状态码采取不同措施:

  • 4xx 客户端错误 (如 400、401、403、404):通常是调用方问题,需检查参数、权限、URL 是否正确,不建议重试(重试也会失败)。
  • 5xx 服务端错误 (如 500、502、503):通常是服务器临时故障,可重试(如间隔 1 秒后重试 2-3 次)。

2. 连接 / 超时异常:重试机制 + 资源释放

网络波动或服务器临时不可达时,重试是有效的恢复手段:

  • 重试间隔采用指数退避策略(如 1 秒→2 秒→4 秒),避免加重服务器负担。
  • 重试次数控制在 3 次以内,防止无限循环。

3. 参数 / 格式异常:提前校验,避免无效请求

调用接口前校验参数合法性(如必填字段是否存在、数据类型是否正确),减少因参数错误导致的失败。

三、实战代码:完整异常处理框架

以下是封装好的接口调用函数,集成了各类异常处理逻辑,可直接复用:

python 复制代码
import requests
import time
from requests.exceptions import (
    HTTPError,
    ConnectionError,
    Timeout,
    RequestException
)

def call_api_with_retry(
    url,
    method="GET",
    params=None,
    json=None,
    headers=None,
    timeout=10,
    max_retries=3,
    retry_delay=1
):
    """
    带异常处理和重试机制的API调用函数
    :param url: 接口URL
    :param method: 请求方法(GET/POST/PUT/DELETE)
    :param params: GET请求参数(字典)
    :param json: POST/PUT请求体(字典,自动转为JSON)
    :param headers: 请求头(字典)
    :param timeout: 超时时间(秒)
    :param max_retries: 最大重试次数(针对5xx和网络异常)
    :param retry_delay: 初始重试间隔(秒,指数退避)
    :return: 接口返回的JSON数据(成功)或None(失败)
    """
    # 初始化请求参数(默认值处理)
    params = params or {}
    json = json or {}
    headers = headers or {"Content-Type": "application/json"}
    retries = 0  # 当前重试次数

    while retries <= max_retries:
        try:
            # 发送请求
            if method.upper() == "GET":
                response = requests.get(
                    url,
                    params=params,
                    headers=headers,
                    timeout=timeout
                )
            elif method.upper() == "POST":
                response = requests.post(
                    url,
                    json=json,
                    headers=headers,
                    timeout=timeout
                )
            else:
                # 支持其他方法(PUT/DELETE等)
                response = requests.request(
                    method,
                    url,
                    json=json,
                    params=params,
                    headers=headers,
                    timeout=timeout
                )

            # 检查HTTP错误状态码(4xx/5xx)
            response.raise_for_status()  # 若状态码>=400,抛出HTTPError

            # 解析JSON响应(若接口返回非JSON,会抛出ValueError)
            return response.json()

        except HTTPError as e:
            # 处理HTTP错误(4xx/5xx)
            status_code = response.status_code
            if 400 <= status_code < 500:
                # 4xx客户端错误:不重试,记录错误后返回
                print(f"客户端错误:{status_code},URL:{url},详情:{str(e)}")
                return None
            elif 500 <= status_code < 600:
                # 5xx服务端错误:可重试
                print(f"服务端错误:{status_code},准备重试({retries}/{max_retries})")
            else:
                print(f"未知HTTP错误:{status_code},详情:{str(e)}")
                return None

        except ConnectionError as e:
            # 处理连接异常(网络问题、服务器不可达)
            print(f"连接失败:{str(e)},准备重试({retries}/{max_retries})")

        except Timeout as e:
            # 处理超时异常
            print(f"请求超时({timeout}秒):{str(e)},准备重试({retries}/{max_retries})")

        except ValueError as e:
            # 处理JSON解析失败(接口返回非JSON格式)
            print(f"响应解析失败(非JSON):{str(e)},URL:{url}")
            return None

        except RequestException as e:
            # 处理其他requests库异常(如URL格式错误)
            print(f"请求异常:{str(e)},URL:{url}")
            return None

        except Exception as e:
            # 处理所有未捕获的异常(兜底)
            print(f"未知错误:{str(e)},URL:{url}")
            return None

        # 重试逻辑(仅当未达到最大重试次数时)
        retries += 1
        if retries > max_retries:
            print(f"已达最大重试次数({max_retries}次),请求失败")
            return None
        # 指数退避:间隔 = 初始延迟 * (2^重试次数)
        delay = retry_delay * (2 **(retries - 1))
        print(f"重试间隔:{delay}秒...")
        time.sleep(delay)

    return None

四、使用示例与效果验证

1. 调用正常接口(成功案例)

python

运行

ini 复制代码
# 调用一个正常的API(如JSONPlaceholder测试接口)
result = call_api_with_retry(
    url="https://jsonplaceholder.typicode.com/posts/1",
    method="GET"
)
if result:
    print("接口返回:", result["title"])  # 输出:sunt aut facere repellat provident occaecati excepturi optio reprehenderit

2. 模拟服务端错误(500 错误,触发重试)

ini 复制代码
# 调用一个模拟500错误的接口(可自行搭建测试接口)
result = call_api_with_retry(
    url="https://httpstat.us/500",  # 该URL固定返回500
    method="GET",
    max_retries=2
)
# 输出日志:
# 服务端错误:500,准备重试(0/2)
# 重试间隔:1秒...
# 服务端错误:500,准备重试(1/2)
# 重试间隔:2秒...
# 已达最大重试次数(2次),请求失败

3. 模拟超时异常(触发重试)

ini 复制代码
# 调用一个模拟超时的接口(延迟15秒返回,超过设置的10秒超时)
result = call_api_with_retry(
    url="https://httpstat.us/200?sleep=15000",  # 延迟15秒
    method="GET",
    timeout=10,
    max_retries=1
)
# 输出日志:
# 请求超时(10秒):HTTPSConnectionPool(...), 准备重试(0/1)
# 重试间隔:1秒...
# 已达最大重试次数(1次),请求失败

五、最佳实践与扩展建议

1.** 日志记录 :将异常详情(时间、URL、错误信息)写入日志文件(如用logging模块),便于事后排查问题。
2.
动态调整重试策略 **:

  • 对核心接口(如支付接口)可提高重试次数(如 5 次),非核心接口降低重试次数(如 2 次)。
  • 根据接口响应时间动态调整超时时间(如正常响应 3 秒的接口,超时设为 5 秒)。
    3.** 资源释放 :若涉及文件上传或长连接,在异常处理中需确保资源正确关闭(如用with语句管理文件流)。
    4.
    告警机制 **:对高频失败的接口(如 10 分钟内失败 10 次)触发告警(如邮件、钉钉通知),及时介入处理。

通过上述异常处理框架,可有效应对 90% 以上的 API 调用问题,显著提升程序的健壮性和稳定性。核心是 "** 分类处理 + 重试策略 + 兜底机制 **",既保证错误可恢复,又避免无效重试浪费资源

相关推荐
sinat_267611911 天前
Trae AI 进行 Android 从0 到 1的一键开发
kotlin·android studio·trae
阆遤2 天前
利用TRAE对nanobot进行安全分析并优化
python·安全·ai·trae·nanobot
Molesidy2 天前
【VSCode】VSCode或者Trae的扩展文件夹以及用户设置文件夹的路径更改到指定位置
ide·编辑器·trae
yosh'joy!!3 天前
下载Trae使用
ai·trae
豆包MarsCode3 天前
只需一个指令,让 OpenClaw 安排 TRAE 干活
trae
sugar15693 天前
Trae快速构建自己项目的docker镜像
docker·容器·trae
sugar15694 天前
Trae 添加项目规则,快速完成crmeb项目本地开发环境搭建
docker·容器·trae
欧简墨4 天前
kotlin Android Extensions插件迁移到viewbinding总结
android·trae
arbboter5 天前
【AI编程】约束即设计:AI时代的人机边界重构
ai编程·ai工作流·人机协作·trae·声明式执行·流程编排
进击的雷神6 天前
Trae AI IDE 完全指南:从入门到精通
大数据·ide·人工智能·trae