4. REST API基础:HTTP协议回顾、RESTful设计原则、请求与响应模型、状态码处理

各位同学好,我是你们的讲师。今天咱们聊聊REST API。说实话,我在做量化交易系统之前,也觉得自己对HTTP挺熟的。直到有一次,我负责对接某交易所的行情接口,因为搞混了状态码,导致整个数据采集模块跑飞了整整一个晚上……嗯,从那以后,我对REST API的每个细节都格外较真。

4.1 HTTP协议回顾

HTTP协议,说白了就是客户端和服务器之间的一种「对话规则」。你发请求,它给响应,就这么简单。但这里面的门道,比你想象的多。

我个人习惯把HTTP协议拆成三个核心部分来看:

  • 请求行:包含方法、URI、协议版本。比如 GET /api/v1/ticker HTTP/1.1
  • 请求头:携带元数据,比如 Content-TypeAuthorization
  • 请求体:实际传输的数据,通常是JSON格式

响应也是类似的套路:状态行 + 响应头 + 响应体。你想想看,交易所每秒要处理成千上万个这样的请求,任何一个环节出问题,都可能造成数据丢失或延迟。

核心要点:HTTP是无状态的。每个请求都是独立的,服务器不会记住你之前的操作。所以每次请求都要带上认证信息——这就是为什么API Key要放在Header里。

4.2 RESTful设计原则

RESTful,说白了就是一套「怎么写API才优雅」的规范。我在项目中遇到过不少「伪RESTful」接口,看着像REST,用起来全是坑。

真正的RESTful设计,要遵循这几个原则:

  1. 资源导向:每个URL代表一个资源,而不是一个操作。比如 /orders 代表订单集合,/orders/12345 代表具体某个订单
  2. 使用标准HTTP方法:GET查、POST增、PUT改、DELETE删。别搞什么 /getOrder/createOrder 这种命名
  3. 无状态通信:服务器不保存客户端状态,所有必要信息都在请求里
  4. 统一接口:所有资源都通过相同的接口规范来操作

我的经验:设计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 知识体系总览

最后,我用一张图把本章的核心内容串起来。这张图是我自己画的,希望能帮你建立整体认知:

REST API 核心知识体系 HTTP协议 RESTful设计 请求与响应 状态码处理 请求行 · 请求头 · 请求体 状态行 · 响应头 · 响应体 无状态 · 明文传输 资源导向 · 标准方法 无状态 · 统一接口 GET/POST/PUT/DELETE URL参数 · Header · Body JSON格式 · 数据类型 认证信息 · 时间戳 2xx成功 · 4xx客户端错误 5xx服务器错误 429频率限制 · 重试策略 核心目标:稳定、高效、可扩展的交易所通信

这张图把咱们今天讲的内容都串起来了。HTTP协议是基础,RESTful设计是规范,请求响应是具体实现,状态码处理是保障。四者缺一不可。

好了,今天就到这里。记住,写代码前先把这些基础打牢,后面遇到问题才不会慌。咱们下节课见。

专注资料整理