GET / POST / PUT 的语义 你真的用对了吗?
你可能觉得 HTTP 方法(GET/POST/PUT/DELETE…)是再基础不过的东西。但恰恰是基础的东西,落地时最容易 一人一个用法 :有人用 GET 干删除、有人用 POST 传一切、有人 PUT 和 POST 一通乱用。这篇聊的是 HTTP 方法在真实开发里的语义,帮你把接口的方法和 它到底该干嘛 对齐,以及那些 看似可以、实际别扭 的常见误区。

一、为什么方法(Method)不是随便挑的
方法和语义绑定,带来的实际好处不是 规范癖 ,而是三点:
- 可读性 :别人看 URL 和方法,就知道这个接口是查、是增、是改、是删。
GET /user/:idvsPOST /user/delete,前者更直接。 - 缓存/CDN :
GET天然可缓存、可被代理、可被收藏,而POST通常不可缓存。给 查 的数据用GET,天然能借到这一层。 - 安全默认 :用
GET做删除,容易被恶意链接、爬虫、误点触发(链接里带了副作用)。用安全的方法并配合鉴权,能守住底线。
二、常用方法的语义速查
| 方法 | 语义 | 典型用法 | 幂等性 |
|---|---|---|---|
| GET | 安全、只读 | 查列表、查单条、查询统计 | 幂等 |
| POST | 创建 / 提交 | 新增资源、表单提交 | 不保证幂等 |
| PUT | 覆盖更新 | 更新整个资源 | 幂等 |
| PATCH | 局部更新 | 只改个别字段 | 幂等(等语义) |
| DELETE | 删除 | 删除资源 | 幂等 |
这里的 幂等 是一个关键概念: 同一个请求重复执行,结果不应该重复产生 。比如:
GET /user/list重复调用,结果一样 → 幂等,安全。POST /order每调一次就新增一单 → 不幂等,所以要防止重复提交。PUT /user/1把用户数据整体覆盖成某一套 → 调几次结果一样 → 幂等。
三、最常见的两种 用反了
误区一:查询用 POST
不少开发图省事,把查询参数塞到 body 用 POST:
POST /user/list
Body: { pageNum: 1, pageSize: 10, keyword: '张三' }问题:POST 本意是 有副作用 / 提交 ,但查询是无副作用的读。用 POST 会失去缓存、失去浏览器地址栏可分享、失去历史回退,还让 查询 和 提交 在语义上混淆。
什么时候 POST 查询合理? 查询条件特别长(接近/超出 URL 长度限制)、条件结构复杂(嵌套对象数组)、或是对外接口约定如此。这种 被迫的例外 是存在的,但 默认还是优先 GET 。
误区二:删除用 POST 或 GET 来做
GET /user/delete?id=1 // 不好:GET 带副作用
POST /user/delete // 勉强:但语义是 删除 ,用 DELETE 更对GET 如果做了删除,浏览器历史、站长机器人、误点链接都可能直接触发,非常危险。 用 GET 做删除 几乎是公认的坏味道。能用 DELETE 就用 DELETE,个别扣兼容的再用 POST 兜底。
四、PUT 还是 PATCH,怎么选
你看接口文档,PUT 和 PATCH 常常被 用 POST / PUT 都行 糊弄过去。但认真讲:
- PUT:整体覆盖 。我来给你 一整套完整的含义 ,缺的字段就填空。
- PATCH:局部更新 。我只想说 把 name 改了 ,其他字段不动。
举例 更新用户资料 :
# PUT:全量提交,我把整套资料都给你
PUT /user/1 { username, nickname, phone, email, ... }
# PATCH:只改手机号
PATCH /user/1 { "phone": "138xxxx" }很多项目从兼容角度干脆只用 PUT,把不传的字段默认 不改 ,这种做法能跑但语义模糊。取舍建议: 如果前端每个编辑页都是 全字段回填 ,用 PUT 就够了,别硬上 PATCH;如果只是碎功能(改个状态、改个备注),用 PATCH 更恰当。
五、RESTful 风格下的 CRUD 映射
配合 RESTful,一个 用户 资源的常规映射长这样(对照真的很直观):
| 场景 | 方法 + 路径 | 说明 |
|---|---|---|
| 查列表 | GET /user/list | 分页列表 |
| 查单条 | GET /user/:id | 取一个 |
| 新增 | POST /user | 新建 |
| 更新(全) | PUT /user/:id 或 PUT /user (id 在 body/front) | 覆盖 |
| 删除 | DELETE /user/:id | 删除 |
有的团队喜欢 PUT /user 把 id 放在 body 里(一件事发一个请求就搞定),有的偏好 PUT /user/:id (id 在路径)。两种都行,关键在 团队统一 ,别一个接口一种。
六、查询 vs 写操作在实际企业的常见妥协
真实项目往往没那么 规矩 ,有几个 公认的妥协 值得知道:
- 没有 DELETE 权限,用 POST 写删除 :很多老接口就这么做,历史原因。
- 查询又长又复杂,用 POST :当作 可接受的例外 。
- 一个接口既处理新增又处理编辑 :根据 body 里有没有 id 判断(有 id → 编辑,无 → 新增)。这种通常用
POST(语义中立),但它把 两种操作 塞一起,测试和幂等都会变复杂,能拆就拆。
这些 妥协 不是不能用,而是要知道 - 妥协的代价是前置约定、幂等、权限都要自己操心。 能严格就严格。
七、小结
HTTP 方法虽基础,但先 语义对齐 再 想当然 是写好接口的第一步:
- 查询用 GET ,写操作用 POST/PUT/PATCH/DELETE ,别让 GET 背 删除 的锅;
- GET 重复幂等、POST 非幂等 ,是 幂等/重复 问题(防重复提交)的根因;
- 全量更新选 PUT ,局部改选 PATCH ,要么统一用一种、别混;
- 路由路径 + 方法加起来才组成语义,保持团队一套 URL 风格。
下一篇,我们聊一个看似不起眼、却能造成 线上事故 的细节 - 路由注册顺序 。同样是 GET 路由,一个动态参数路由可能把其它具体接口给 吃 了。






