3. API数据源接入:RESTful API基础、鉴权方式、请求限流与重试策略
做金融数据工程,说白了就是跟各种数据源打交道。而API,尤其是RESTful API,是我们最常碰到的数据接口。我刚开始做量化数据接入那会儿,觉得调API不就是发个HTTP请求嘛,有啥难的?结果第一个月就被各种鉴权失败、限流打回、超时重试搞得焦头烂额。嗯,今天咱们就把这块硬骨头啃下来。
3.1 RESTful API基础:你每天都在用的“快递服务”
RESTful API,你可以把它想象成一个快递服务。你(客户端)要寄东西(数据请求),快递公司(服务器)按规则处理,最后把包裹(数据响应)送到你手上。这个规则就是REST架构。
核心就四个动作,对应HTTP的四个方法:
- GET:查数据。比如查某只股票的历史行情。
- POST:创建数据。比如提交一个交易策略。
- PUT:更新数据。比如修改策略参数。
- DELETE:删除数据。比如取消一个订单。
在金融场景里,我们90%的时间都在用GET。为什么?因为数据源是只读的,我们只管拉数据,不改数据。举个例子,拉取A股实时行情:
GET https://api.example.com/v1/stock/sh600519/quote
返回的JSON大概长这样:
{
"code": "600519",
"name": "贵州茅台",
"price": 1888.88,
"timestamp": "2025-01-15T14:30:00Z"
}
这里有个小细节——URL设计。好的API,URL就是一张数据地图。我见过有些金融数据源把参数全塞在URL路径里,比如/api/getStock?code=600519&type=1&format=json,这种设计说实话很糟糕。我个人习惯用RESTful风格:/api/v1/stocks/600519/quote,路径清晰,版本号也带上,方便以后升级。
3.2 鉴权方式:API Key vs OAuth,怎么选?
数据源不是谁都能随便调的,得有“通行证”。金融数据源的鉴权,主流就两种:API Key和OAuth。
3.2.1 API Key:简单粗暴,适合内部系统
API Key就是一个字符串,相当于你的身份证号。每次请求时,要么放在请求头里,要么放在URL参数里。
# 放在请求头(推荐)
GET /v1/stock/sh600519/quote HTTP/1.1
Host: api.example.com
X-API-Key: your-api-key-here
# 放在URL参数(不推荐,容易被日志泄露)
GET /v1/stock/sh600519/quote?api_key=your-api-key-here
为什么推荐放请求头?因为URL参数会被服务器日志、浏览器历史记录、代理服务器等记录下来,API Key就裸奔了。我在一个项目里就吃过这个亏——同事把API Key直接拼在URL里,结果日志系统被攻破,Key被滥用,一天跑了10万次请求,直接被数据源封了IP。
3.2.2 OAuth 2.0:安全灵活,适合第三方应用
OAuth 2.0就复杂多了。它不直接暴露你的密码,而是通过一个“授权码”换“令牌”。流程大概是:
- 你(客户端)向授权服务器请求授权码。
- 用户同意后,授权服务器给你一个授权码。
- 你用授权码去换访问令牌(Access Token)。
- 拿着令牌去调API。
金融数据源里,OAuth常用于券商接口、银行数据接口。比如你要接入某券商的交易API,就得走OAuth流程。令牌有过期时间,一般1小时到24小时不等,过期了得用刷新令牌(Refresh Token)重新获取。
# 获取令牌的请求示例
POST https://api.example.com/oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=your-authorization-code
&client_id=your-client-id
&client_secret=your-client-secret
&redirect_uri=https://yourapp.com/callback
返回的令牌:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "def50200..."
}
我个人建议:内部系统用API Key,外部第三方用OAuth。别为了省事把OAuth搞成API Key,那安全性就大打折扣了。
3.3 请求限流与重试策略:别把自己玩死
金融数据源不是无限量供应的。你想想看,如果每个用户都疯狂请求,服务器早崩了。所以数据源会限流——比如每分钟最多100次请求,或者每秒最多5次。
3.3.1 限流策略:怎么优雅地“排队”
常见的限流方式有三种:
| 限流方式 | 说明 | 金融场景举例 |
|---|---|---|
| 固定窗口 | 每分钟/每小时固定次数 | 某数据源:每分钟100次 |
| 滑动窗口 | 按时间窗口滑动计数 | 某交易所:每秒5次,超出则429 |
| 令牌桶 | 按速率生成令牌,有令牌才能请求 | 某行情服务:每秒10个令牌,突发可到20 |
怎么应对限流?我常用的方法:
- 加延迟:每次请求后sleep一下,比如每秒最多5次,那就sleep 0.2秒。
- 读响应头:很多API会在响应头里告诉你限流信息,比如
X-RateLimit-Remaining、X-RateLimit-Reset。我习惯先读这些头,动态调整请求频率。 - 退避策略:如果收到429(Too Many Requests),就等一会儿再试。等多久?看
Retry-After头。
# Python示例:带限流控制的请求
import time
import requests
def fetch_with_rate_limit(url, api_key, max_retries=3):
for attempt in range(max_retries):
resp = requests.get(url, headers={"X-API-Key": api_key})
if resp.status_code == 200:
return resp.json()
elif resp.status_code == 429:
retry_after = int(resp.headers.get("Retry-After", 5))
print(f"被限流了,等{retry_after}秒再试...")
time.sleep(retry_after)
else:
print(f"请求失败:{resp.status_code}")
break
return None
3.3.2 重试策略:失败不可怕,可怕的是乱重试
网络请求总会失败。超时、连接重置、服务器500...这些在金融数据接入里太常见了。但重试不是无脑重试,得讲究策略。
我总结了一个“三三制”重试原则:
- 最多重试3次:超过3次,大概率是数据源挂了,别浪费资源。
- 每次间隔翻倍:第一次等1秒,第二次等2秒,第三次等4秒。这叫指数退避。
- 只重试可恢复的错误:429(限流)、500(服务器内部错误)、503(服务不可用)可以重试。但400(参数错误)、401(鉴权失败)就别重试了,重试一万次也没用。
# Python示例:带指数退避的重试
import time
import requests
def fetch_with_retry(url, api_key, max_retries=3):
for attempt in range(max_retries):
try:
resp = requests.get(url, headers={"X-API-Key": api_key}, timeout=5)
if resp.status_code == 200:
return resp.json()
elif resp.status_code in [429, 500, 502, 503]:
wait = 2 ** attempt # 指数退避:1, 2, 4秒
print(f"第{attempt+1}次失败,等{wait}秒重试...")
time.sleep(wait)
else:
print(f"不可重试的错误:{resp.status_code}")
break
except requests.exceptions.Timeout:
wait = 2 ** attempt
print(f"请求超时,等{wait}秒重试...")
time.sleep(wait)
return None
3.4 知识体系总览:一张图看懂API数据源接入
说了这么多,咱们用一张SVG图把整个流程串起来。从请求发出到数据落地,每一步都有坑,每一步都有技巧。
这张图把整个流程分成了6步。你想想看,从构建请求到数据落地,每一步都可能出问题。但只要你把鉴权、限流、重试这三个核心点抓牢了,80%的坑都能避开。
好了,API数据源接入这块就聊到这儿。记住:RESTful API是基础,鉴权是门槛,限流和重试是保命符。把这套组合拳打好了,金融数据接入就稳了。