共计 3204 个字符,预计需要花费 9 分钟才能阅读完成。
为什么需要 API 调用工具
在项目开发中,直接使用原生 HTTP 库调用 API 会遇到三个典型问题:

- 认证复杂性:特别是 OAuth2.0/JWT 等流程,手动处理 token 刷新非常麻烦
- 网络不可靠性:超时、重试逻辑若实现不当,会导致业务异常
- 资源竞争:并发控制不好可能触发服务器限流(rate limiting)
技术选型:Requests vs urllib
Python 生态中有两个主流 HTTP 库:
urllib标准库:功能基础,需要手动处理连接池、重定向等逻辑Requests第三方库:- 自动管理 Keep-Alive 连接复用
- 支持 Session 级配置(超时、认证等)
- 更人性化的 API 设计
推荐使用 Requests+Session 管理长期连接,实测可提升约 30% 的 QPS:
import requests
# 错误示范:每次创建新连接
for _ in range(100):
requests.get('https://api.example.com') # 性能低下
# 正确做法:使用 Session 复用连接
with requests.Session() as s:
for _ in range(100):
s.get('https://api.example.com') # 复用 TCP 连接
核心实现技巧
1. OAuth2.0 自动刷新
以下封装类会在 token 过期时自动刷新:
class OAuthClient:
def __init__(self, client_id, client_secret):
self.token = None
self.refresh_token = os.getenv('OAUTH_REFRESH_TOKEN') # 从环境变量读取
def _refresh_token(self):
# 实际项目应使用加密存储
payload = {
'grant_type': 'refresh_token',
'refresh_token': self.refresh_token
}
resp = requests.post(TOKEN_URL, data=payload)
resp.raise_for_status() # 关键:检查 HTTP 错误
self.token = resp.json()['access_token']
def call_api(self, url):
if not self.token:
self._refresh_token()
try:
return requests.get(url, headers={'Authorization': f'Bearer {self.token}'
})
except requests.HTTPError as e:
if e.response.status_code == 401: # Token 过期
self._refresh_token()
return self.call_api(url) # 重试
raise
2. 速率限制装饰器
使用线程安全的令牌桶算法:
from threading import Lock
import time
class RateLimiter:
def __init__(self, calls_per_second):
self.period = 1 / calls_per_second
self.last_called = 0
self.lock = Lock()
def __call__(self, func):
def wrapped(*args, **kwargs):
with self.lock:
elapsed = time.time() - self.last_called
if elapsed < self.period:
time.sleep(self.period - elapsed)
self.last_called = time.time()
return func(*args, **kwargs)
return wrapped
# 使用示例:限制每秒 5 次调用
@RateLimiter(5)
def call_api():
return requests.get('https://api.example.com')
3. 异常处理最佳实践
try:
response = requests.get(url, timeout=10)
response.raise_for_status() # 自动转换 HTTP 错误为异常
data = response.json()
except requests.exceptions.RequestException as e:
logger.error(f"API 调用失败: {str(e)}")
raise
性能优化
重试策略对比
| 策略类型 | 示例间隔序列 | 适用场景 |
|---|---|---|
| 固定间隔 | 1s, 1s, 1s | 低敏感度 API |
| 线性递增 | 1s, 2s, 3s | 中等敏感度 |
| 指数退避 | 1s, 2s, 4s | 高负载系统(推荐) |
使用 backoff 库实现指数退避:
import backoff
@backoff.on_exception(
backoff.expo,
requests.exceptions.RequestException,
max_tries=3
)
def call_api():
return requests.get(url)
安全实践
1. 敏感信息存储
# 错误做法:硬编码在代码中
CLIENT_SECRET = 'abc123' # 会被 git 记录
# 正确做法:使用环境变量
import os
from cryptography.fernet import Fernet
key = Fernet.generate_key()
cipher = Fernet(key)
encrypted = cipher.encrypt(b"secret_value")
os.environ['API_SECRET'] = encrypted.decode()
2. SSL 证书验证
# 严格模式(生产环境推荐)requests.get(url, verify='/path/to/ca_bundle.pem')
# 调试模式(仅开发使用)requests.get(url, verify=False) # 不安全!
生产检查清单
日志规范
- 记录请求参数(脱敏后)
- 记录响应时间、状态码
- 错误日志包含完整堆栈
示例:
logger.info(f"调用 API: {url} 耗时{response.elapsed.total_seconds()}s"
)
Prometheus 监控指标
from prometheus_client import Counter, Histogram
API_CALLS = Counter('api_calls_total', 'Total API calls', ['endpoint', 'status'])
API_LATENCY = Histogram('api_latency_seconds', 'API latency', ['endpoint'])
@API_LATENCY.time()
def call_api():
try:
response = requests.get(url)
API_CALLS.labels(url, 'success').inc()
return response
except:
API_CALLS.labels(url, 'failed').inc()
raise
熔断器 (Circuit Breaker) 配置
推荐使用pybreaker:
from pybreaker import CircuitBreaker
breaker = CircuitBreaker(
fail_max=5, # 连续失败 5 次触发熔断
reset_timeout=60 # 60 秒后尝试恢复
)
@breaker
call_api()
总结建议
- 始终使用 Session 管理连接
- 实现自动化的 token 刷新机制
- 为不同 API 配置合适的重试策略
- 生产环境必须开启证书验证
- 监控指标需要包含成功率、延迟、熔断状态
这些实践来自笔者多个项目的经验总结,特别适用于需要对接第三方 API 的中大型系统。根据实际业务需求,可以进一步扩展为分布式限流、异步调用等高级模式。
正文完
