4. REST API基础:HTTP协议回顾、RESTful设计原则、请求与响应模型、状态码处理
各位同学好,我是你们的讲师。今天咱们聊聊REST API。说实话,我在做量化交易系统之前,也觉得自己对HTTP挺熟的。直到有一次,我负责对接某交易所的行情接口,因为搞混了状态码,导致整个数据采集模块跑飞了整整一个晚上……嗯,从那以后,我对REST API的每个细节都格外较真。
4.1 HTTP协议回顾
HTTP协议,说白了就是客户端和服务器之间的一种「对话规则」。你发请求,它给响应,就这么简单。但这里面的门道,比你想象的多。
我个人习惯把HTTP协议拆成三个核心部分来看:
- 请求行:包含方法、URI、协议版本。比如
GET /api/v1/ticker HTTP/1.1 - 请求头:携带元数据,比如
Content-Type、Authorization - 请求体:实际传输的数据,通常是JSON格式
响应也是类似的套路:状态行 + 响应头 + 响应体。你想想看,交易所每秒要处理成千上万个这样的请求,任何一个环节出问题,都可能造成数据丢失或延迟。
核心要点:HTTP是无状态的。每个请求都是独立的,服务器不会记住你之前的操作。所以每次请求都要带上认证信息——这就是为什么API Key要放在Header里。
4.2 RESTful设计原则
RESTful,说白了就是一套「怎么写API才优雅」的规范。我在项目中遇到过不少「伪RESTful」接口,看着像REST,用起来全是坑。
真正的RESTful设计,要遵循这几个原则:
- 资源导向:每个URL代表一个资源,而不是一个操作。比如
/orders代表订单集合,/orders/12345代表具体某个订单 - 使用标准HTTP方法:GET查、POST增、PUT改、DELETE删。别搞什么
/getOrder、/createOrder这种命名 - 无状态通信:服务器不保存客户端状态,所有必要信息都在请求里
- 统一接口:所有资源都通过相同的接口规范来操作
我的经验:设计REST API时,先把资源列出来,再想操作。别一上来就写代码,否则后面改起来很痛苦。
4.3 请求与响应模型
咱们拿交易所的行情接口举个例子。一个典型的REST请求长这样:
GET /api/v1/ticker?symbol=BTCUSDT HTTP/1.1
Host: api.exchange.com
X-MBX-APIKEY: your_api_key_here
Content-Type: application/json
对应的响应可能是:
HTTP/1.1 200 OK
Content-Type: application/json
{
"symbol": "BTCUSDT",
"price": "50000.00",
"volume": "1234.56",
"timestamp": 1623456789
}
这里有个细节要注意:请求参数和请求体是两回事。GET请求的参数在URL里,POST/PUT的参数在请求体里。我曾经见过有人把POST的参数也塞进URL,结果被网关截断了——嗯,血的教训。
4.4 状态码处理
状态码是服务器给你的「暗号」。每个数字都有特定含义。我整理了一张表,建议你收藏:
| 状态码 | 含义 | 常见场景 |
|---|---|---|
| 200 | OK | 请求成功,返回数据 |
| 201 | Created | 创建订单成功 |
| 204 | No Content | 删除成功,无返回体 |
| 400 | Bad Request | 参数错误、格式不对 |
| 401 | Unauthorized | API Key无效或过期 |
| 403 | Forbidden | 权限不足,比如IP白名单限制 |
| 404 | Not Found | 资源不存在 |
| 429 | Too Many Requests | 触发频率限制 |
| 5xx | Server Error | 交易所服务器内部问题 |
避坑指南:我曾经因为没处理429状态码,导致程序被交易所封了IP。记住,遇到429要退避重试,别硬冲。另外,5xx错误要区分是临时故障还是永久故障,处理策略完全不同。
写代码时,我建议你这样处理状态码:
import requests
def fetch_ticker(symbol):
url = f"https://api.exchange.com/api/v1/ticker?symbol={symbol}"
headers = {"X-MBX-APIKEY": "your_api_key"}
resp = requests.get(url, headers=headers)
if resp.status_code == 200:
return resp.json()
elif resp.status_code == 429:
# 触发频率限制,等待后重试
time.sleep(1)
return fetch_ticker(symbol)
elif resp.status_code >= 500:
# 服务器错误,记录日志并告警
logger.error(f"Server error: {resp.status_code}")
return None
else:
# 其他错误,抛出异常
resp.raise_for_status()
你想想看,如果不对状态码做精细化处理,一旦交易所接口出问题,你的程序可能就傻傻地一直重试,或者直接崩溃。这在量化交易里是绝对不能接受的。
4.5 知识体系总览
最后,我用一张图把本章的核心内容串起来。这张图是我自己画的,希望能帮你建立整体认知:
这张图把咱们今天讲的内容都串起来了。HTTP协议是基础,RESTful设计是规范,请求响应是具体实现,状态码处理是保障。四者缺一不可。
好了,今天就到这里。记住,写代码前先把这些基础打牢,后面遇到问题才不会慌。咱们下节课见。