RESTful 接口概述
聊 REST 之前,我先问个问题:你写 API 的时候,是不是也经常跟同事吵“这个接口该用 GET 还是 POST”?我以前在团队里就因为这个吵过好几次。后来想明白了,不是因为谁对谁错,而是大家对 REST 的理解不太一样。今天咱们就把 RESTful 接口这块理清楚——REST 风格、HTTP 方法、核心设计原则,我会结合自己踩过的坑来讲。
REST 架构风格
REST,全称是 Representational State Transfer,翻译过来叫“表述性状态转移”。这名字挺绕,说白了就是一种设计 Web 接口的风格。它不强制你用特定的协议或工具,但定了一套约束——只要你遵守这些约束,你的 API 就是 RESTful 的。
我记得 2016 年刚接手一个电商项目,负责人说“我们要做 RESTful API”。结果我看他们接口:订单列表用 GET /order/list,删除订单用 GET /order/delete?id=123。这哪是 REST 啊?这是 RPC 披了个 REST 的马甲。
POST /api,用请求体里的 action 字段区分增删改查——那叫 RPC 风格,不叫 REST。
HTTP 方法与资源操作映射
RESTful 接口里,HTTP 方法就是动词,资源 URI 就是名词。常用的就这五个:
| HTTP 方法 | 操作类型 | 典型 URI(以用户资源为例) | 响应状态码 |
|---|---|---|---|
GET |
查询/读取 | GET /users 或 GET /users/{id} |
200 OK |
POST |
创建新资源 | POST /users |
201 Created |
PUT |
完全替换资源 | PUT /users/{id} |
200 OK 或 204 No Content |
PATCH |
部分更新资源 | PATCH /users/{id} |
200 OK |
DELETE |
删除资源 | DELETE /users/{id} |
204 No Content |
注意 PUT 和 PATCH 的区别。一次重构的时候,我用 PUT 做部分更新,结果下游用旧数据把整条记录覆盖了……自那以后我再也不敢把 PUT 当成“更新”来用,它本质是“替换”。PATCH 才是部分更新,不过很多框架对 PATCH 支持不友好,得自己写序列化逻辑。
RESTful 设计原则归纳
光知道 HTTP 方法还不够,RESTful 还有几条硬性原则。我把它们总结成一张表,每条后面附一句我的真实体会。
| 原则 | 说明 | 我的经历 |
|---|---|---|
| 资源导向 | 用名词定义 URI,比如 /orders,不用动词 /getOrders |
以前接手过一个项目,URI 全是 /api/getOrderList,改起来想吐血。 |
| 无状态 | 每个请求包含全部上下文,服务端不存会话 | 我们做支付回调时,一开始把用户状态存在 session 里,结果横向扩展后全乱套了。 |
| 统一接口 | 用标准 HTTP 方法 + 标准状态码 + 标准媒体类型 | 我习惯让所有接口都返回 application/json,版本号放在 Accept 头里。 |
| 超媒体驱动(HATEOAS) | 响应中返回链接,指导客户端下一步操作 | 真正做 HATEOAS 的项目很少,但小圈子内用 _links 字段很管用。 |
| 分层系统 | 客户端不知道它直接连的是服务器还是网关 | 我们在网关层做了流量染色和国密验签,客户端无感知,这很优雅。 |
实际接口长什么样?
我们写个简单的示例,请求一个订单资源:
# 创建订单
POST /orders
Content-Type: application/json
Accept: application/json
{
"userId": 1024,
"items": [
{"sku": "B-001", "quantity": 2},
{"sku": "B-002", "quantity": 1}
]
}
响应:
HTTP/1.1 201 Created
Location: /orders/3001
Content-Type: application/json
{
"orderId": 3001,
"userId": 1024,
"status": "pending",
"totalAmount": 45.00,
"_links": {
"self": {"href": "/orders/3001"},
"payment": {"href": "/orders/3001/payment"}
}
}
你看,响应里给了 _links,客户端接下来可以直接去 /orders/3001/payment 发起支付,不需要从页面里拼 URL。这就是超媒体驱动的味道——虽然现实中很少有团队完全做到,但熟悉这个思想对理解 REST 很有帮助。
/order/cancel 就是反例,正确的做法是 PATCH /orders/{id} 并带上 {"status": "cancelled"}。我第一次写 REST API 时也犯过这错,后来被 code review 打回来改的。
本章小结
RESTful 接口设计说白了就是 “用 HTTP 规范来表达资源操作”。记住三点:资源用名词、动词用方法、状态码要准确。后面几章我们会结合国密算法来封装这些接口——签名、验签、加密、解密,都会用到今天讲的 REST 原则。嗯,一开始可能觉得约束多,但用习惯了你会发现,RESTful 风格能让你的接口像文档一样清晰。