2. HTTP 方法与状态码:GET、POST、PUT、DELETE、PATCH详解,常用状态码及其含义
聊到RESTful API,最核心的其实就是两件事:用什么方法,以及返回什么状态。
我刚开始写API的时候,也犯过糊涂——明明只是更新一个字段,到底该用PUT还是PATCH?状态码更是五花八门,有人用200表示创建成功,有人用201。嗯,今天咱们就把这些彻底理清楚。
2.1 HTTP方法:API的动词
HTTP方法,说白了就是告诉服务器「你想干什么」。RESTful风格里,每个方法都有明确的语义,别乱用。
2.1.1 GET:获取资源
最常用的方法,没有之一。GET请求应该是幂等的——你调一次和调一百次,结果一样。而且GET请求不应该改变服务器状态。
核心原则:GET只读,不写。
我在项目中遇到过有人用GET请求传JSON body来查询复杂条件。嗯,这其实不太规范。GET的参数应该放在URL的query string里,或者用路径参数。
// 好的做法
GET /api/users?page=1&limit=20
// 也可以
GET /api/users/123
2.1.2 POST:创建资源
POST是「非幂等」的。什么意思?你调一次创建一个用户,调两次就创建两个。所以不要用POST做查询,虽然技术上能实现,但语义上不对。
我个人习惯:POST只用来创建资源,或者执行那些「不幂等」的操作。
POST /api/users
Content-Type: application/json
{
"name": "张三",
"email": "zhangsan@example.com"
}
小技巧:POST请求的响应应该返回201 Created,并在Location头里带上新资源的URL。
2.1.3 PUT:全量更新
PUT是幂等的。你调一次和调十次,最终结果一样。它做的是「全量替换」——客户端要提供完整的资源数据。
我曾经见过有人用PUT只传一个字段,结果其他字段全被清空了。嗯,这就是没搞懂PUT的语义。
// 全量更新用户信息
PUT /api/users/123
Content-Type: application/json
{
"name": "李四",
"email": "lisi@example.com",
"age": 30
}
注意:PUT要求客户端提供完整的资源表示。如果只更新部分字段,请用PATCH。
2.1.4 DELETE:删除资源
DELETE也是幂等的。删一次和删十次,结果都是「资源不存在」。但注意,第一次返回204,第二次可能返回404——这并不违反幂等性,因为服务器状态最终是一样的。
DELETE /api/users/123
我个人习惯:删除成功后返回204 No Content,不返回body。如果资源不存在,返回404。
2.1.5 PATCH:部分更新
PATCH是PUT的补充。它只更新客户端提供的字段,其他字段保持不变。你想想看,如果用户只想改个昵称,你让他传整个用户对象,是不是太浪费了?
// 只更新昵称
PATCH /api/users/123
Content-Type: application/json
{
"nickname": "小王"
}
避坑指南:我曾经在项目里用PUT做部分更新,结果前端漏传字段,导致数据丢失。后来全部改成PATCH,问题就解决了。
2.2 常用状态码:API的形容词
状态码告诉客户端「结果怎么样」。选对了状态码,API的语义就清晰了一半。
| 状态码 | 含义 | 使用场景 |
|---|---|---|
| 200 OK | 请求成功 | GET、PUT、PATCH成功时返回 |
| 201 Created | 资源创建成功 | POST创建资源成功后返回 |
| 204 No Content | 请求成功,无返回内容 | DELETE成功,或某些PUT/PATCH |
| 301 Moved Permanently | 资源永久重定向 | API版本迁移 |
| 302 Found | 资源临时重定向 | 临时跳转 |
| 400 Bad Request | 客户端请求错误 | 参数校验失败、格式错误 |
| 401 Unauthorized | 未认证 | 缺少或无效的认证信息 |
| 403 Forbidden | 无权限 | 认证通过但权限不足 |
| 404 Not Found | 资源不存在 | 请求的资源路径错误 |
| 405 Method Not Allowed | 方法不允许 | 对只读资源使用POST |
| 409 Conflict | 资源冲突 | 唯一约束冲突、版本冲突 |
| 422 Unprocessable Entity | 请求语义错误 | 验证失败但格式正确 |
| 429 Too Many Requests | 请求频率过高 | 限流触发 |
| 500 Internal Server Error | 服务器内部错误 | 未捕获的异常 |
| 502 Bad Gateway | 网关错误 | 上游服务不可用 |
| 503 Service Unavailable | 服务暂时不可用 | 维护中、过载 |
2.3 实战中的选择策略
光记住状态码还不够,关键是怎么用。我总结了几条实战经验:
2.3.1 方法+状态码的组合
不同的方法,返回的状态码也有讲究:
- GET:成功返回200,资源不存在返回404
- POST:创建成功返回201,参数错误返回400
- PUT:更新成功返回200,资源不存在可以返回404或创建后返回201
- PATCH:更新成功返回200,如果返回空body可以用204
- DELETE:删除成功返回204,资源不存在返回404
2.3.2 错误响应的body设计
状态码只告诉「对错」,body要告诉「为什么错」。我习惯这样设计:
{
"error": {
"code": "USER_NOT_FOUND",
"message": "用户ID 123 不存在",
"details": "请检查用户ID是否正确"
}
}
提示:错误码用大写字母+下划线,方便前端做国际化。message给用户看,details给开发者看。
2.3.3 避坑指南
我曾经在项目里犯过这些错,你注意避开:
- 别用200表示所有成功——创建资源就该用201,语义清晰
- 别滥用500——参数校验失败返回400,别扔500
- 别忽略405——如果只支持GET,对POST请求返回405
- 别把401和403搞混——401是没登录,403是登录了但没权限
2.4 小结
HTTP方法和状态码,是RESTful API的基石。你想想看,如果连这些基础都搞混了,API的语义就会变得模糊,前端对接起来也痛苦。
我个人建议:先定方法,再选状态码。方法决定了操作类型,状态码描述了操作结果。两者配合好了,你的API就是「自文档化」的——看一眼就知道发生了什么。
下一章咱们聊聊URL设计,那也是个容易踩坑的地方。