2、RESTful API 设计哲学:资源、动词、状态码,你真的懂 REST 吗?
REST,全称 Representational State Transfer,翻译过来是「表述性状态转移」。这名字听着挺绕,说白了就是一种 API 的设计风格。很多人觉得 REST 就是 URL 里用名词、用 GET/POST/PUT/DELETE 就完事了。嗯,我刚开始也这么想,直到在项目里踩了坑才明白——REST 没那么简单。
这一章,咱们就聊聊 REST 的核心三要素:资源、动词、状态码。我会结合自己踩过的坑,帮你把 REST 真正搞明白。
2.1 资源:一切皆资源
REST 的核心思想,是把服务端的一切数据都抽象为「资源」。资源可以是用户、订单、文章、图片……任何你能想到的业务实体。
每个资源都有一个唯一的标识符,通常就是 URL。比如:
GET /users/123 # 获取用户 123
GET /orders/456 # 获取订单 456
GET /articles/789 # 获取文章 789
这里有个关键点:URL 里只用名词,不用动词。为什么?因为动词代表操作,而操作应该由 HTTP 方法来表达。你想想看,如果 URL 里既有名词又有动词,那设计就乱套了。
GET /getUser?id=123
POST /createUser
POST /deleteUser?id=123
这完全违背了 REST 的哲学。URL 里的 getUser、createUser 都是动词,应该用 HTTP 方法来区分。
资源还有层级关系。比如一个用户下的订单:
GET /users/123/orders # 用户 123 的所有订单
GET /users/123/orders/456 # 用户 123 的订单 456
这种层级结构很直观,也符合业务逻辑。我个人习惯把资源层级控制在 3 层以内,太深了反而难维护。
2.2 动词:HTTP 方法的正确用法
HTTP 提供了多种方法,REST 里最常用的是这 5 个:
| HTTP 方法 | 操作 | 幂等 | 安全 | 典型场景 |
|---|---|---|---|---|
| GET | 查询资源 | 是 | 是 | 获取用户列表、获取订单详情 |
| POST | 创建资源 | 否 | 否 | 创建新用户、提交订单 |
| PUT | 全量更新资源 | 是 | 否 | 更新用户全部信息 |
| PATCH | 部分更新资源 | 否 | 否 | 更新用户邮箱 |
| DELETE | 删除资源 | 是 | 否 | 删除用户、取消订单 |
这里有个容易混淆的点:PUT 和 PATCH 的区别。PUT 是全量替换,你传什么,服务端就存什么。PATCH 是部分更新,只修改你传的字段。
我在项目中遇到过一个问题:客户端用 PUT 只传了邮箱字段,结果服务端把其他字段都清空了。这就是没搞懂 PUT 的语义。后来我强制要求:全量更新用 PUT,部分更新用 PATCH。
2.3 状态码:让客户端看懂你的意图
状态码是服务端和客户端沟通的「语言」。选对了状态码,客户端不用看响应体就知道发生了什么。
我见过很多 API 不管成功失败都返回 200,然后在 body 里塞一个 code 字段。这其实是在「绕过」HTTP 协议。你想想看,如果所有请求都返回 200,那客户端还得解析 body 才知道是成功还是失败,多此一举。
常用的状态码就这几个:
| 状态码 | 含义 | 典型场景 |
|---|---|---|
| 200 OK | 请求成功 | GET 查询成功、PUT 更新成功 |
| 201 Created | 资源创建成功 | POST 创建用户成功 |
| 204 No Content | 请求成功,无返回体 | DELETE 删除成功 |
| 400 Bad Request | 客户端请求有误 | 参数校验失败、JSON 格式错误 |
| 401 Unauthorized | 未认证 | 缺少 或 过期 |
| 403 Forbidden | 无权限 | 普通用户尝试删除管理员 |
| 404 Not Found | 资源不存在 | 查询不存在的用户 ID |
| 409 Conflict | 资源冲突 | 创建重复的用户名 |
| 500 Internal Server Error | 服务端内部错误 | 数据库连接失败、未捕获异常 |
这里有个细节:201 Created 要返回 Location 头,告诉客户端新资源的 URL。比如:
HTTP/1.1 201 Created
Location: /users/123
Content-Type: application/json
{
"id": 123,
"name": "张三",
"email": "zhangsan@example.com"
}
这样客户端就知道新资源在哪了。我曾经见过很多 API 返回 201 但不带 Location,客户端还得自己拼 URL,这就不够「RESTful」了。
2.4 RESTful API 的核心流程
说了这么多,咱们用一张图把 RESTful API 的核心流程串起来:
这张图展示了 RESTful API 的完整流程:客户端发起 HTTP 请求,服务端根据 URL 定位到资源,执行对应操作,然后返回带状态码的响应。每一步都有明确的语义,这就是 REST 的魅力。
2.5 常见误区与避坑指南
说了这么多,咱们总结几个常见的误区:
- 误区一:URL 里用动词。比如
/getUser、/createOrder。正确做法是用名词,动词交给 HTTP 方法。 - 误区二:所有请求都返回 200。比如删除成功返回 200,参数错误也返回 200。正确做法是用 204、400、404 等状态码区分。
- 误区三:忽略幂等性。比如用 POST 做更新操作,导致重复请求时数据不一致。正确做法是更新用 PUT(幂等),创建用 POST(非幂等)。
- 误区四:资源层级过深。比如
/users/123/orders/456/items/789。我个人建议层级不超过 3 层,太深了可以用查询参数简化。