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设计,那也是个容易踩坑的地方。