在使用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 调用问题,显著提升程序的健壮性和稳定性。核心是 "** 分类处理 + 重试策略 + 兜底机制 **",既保证错误可恢复,又避免无效重试浪费资源。