深蓝黑背景封面:左侧大标题「不只会 GET 和 POST」,副标题「HTTP 方法语义、幂等性与 API 设计规范」;右侧原创示意图——五枚方法徽章 GET、PUT、PATCH、POST、DELETE 排成一列,GET、PUT、DELETE 标青色对勾表示幂等,POST、PATCH 标紫色问号表示不保证;左上标注「知识专栏 · API 设计」,右上标注「Day 02 · 10-20」 图 1:本文封面,五个方法徽章里藏着今天的主题词——幂等性。

「GET 和 POST 有什么区别」这道经典题,核心考点是语义与幂等性的差异,逐项对照我们之前已经拆解过,本文不再重复。今天把镜头拉远:HTTP 不只有两个方法,而是一整套语义谱系;看懂它,设计 API 时方法、状态码、资源命名该怎么选,就有了统一的标尺。

结论先行:HTTP 方法是给「动作」标成语义的词汇表,幂等性是其中工程价值最高的一维;设计 REST 风格 API,本质是先用资源名词表达业务,再用方法的语义承载动作,最后靠幂等性兜住重试与去重。

第一把标尺:安全性与幂等性。

RFC 9110 给方法定义了两个正交属性。安全(safe):方法语义上是只读的,不改变资源状态——GET、HEAD 属于此类;服务端记日志这类附带动作不算违反安全性。幂等(idempotent):同一个请求执行一次和执行 N 次,对服务器的预期效果相同。RFC 9110 明确划定:PUT、DELETE 和所有安全方法都是幂等的;POST 不是;PATCH 默认也不保证幂等。

幂等性为什么值钱?RFC 9110 自己点破了:幂等方法在通信故障后可以安全地自动重试——客户端发了 PUT 没收到响应,换条连接再发一次,效果不变;而非幂等请求客户端不应自动重试,除非有办法确认原请求没被执行过。代理更是被明确禁止自动重试非幂等请求。重试策略、消息去重、防重复扣费,全部建立在这一条上。

五个方法的语义谱系。

GET:获取资源的当前表示,安全且幂等,响应可被缓存——它吃得到整个 HTTP 缓存体系的红利。PUT:用请求体整体替换目标资源,幂等——放两遍和放一遍结果一样,适合「全量更新」。PATCH:对资源做增量修改,不保证幂等——「给库存加一」执行两次加两次,除非你的 Patch 文档本身设计成幂等操作。POST:让服务端按自身语义处理提交的数据,不幂等——创建子资源、触发动作都归它,是语义最宽的「兜底方法」。DELETE:删除资源,幂等——重复删除一个已不存在的资源,结果状态相同(响应码可能从 200 变 404,但那是响应差异,不是状态差异)。

一个具体例子能把 PUT 和 PATCH 的分界说清楚:更新用户资料时,客户端提交「整个新资料对象」覆盖旧对象,这是 PUT,天然幂等;而「给账户余额加 100」这种增量指令只能走 PATCH 或 POST,它执行两次余额就加两次——所以凡是不幂等的写,都要在协议层面补一个幂等键,把「执行过没有」变成可查询的事实。

谱系加决策路径图:左侧五方法对照——GET(安全且幂等,只读)、PUT(幂等,整量替换)、PATCH(不保证幂等,增量修改)、POST(不幂等,创建或触发动作)、DELETE(幂等,重复删除结果相同)。右侧 API 设计三步决策:动作能不能用资源名词表达?能则用方法与状态码,不能才考虑动作式端点;重复请求会不会出错?会出错的操作要么选幂等方法,要么加幂等键;最后状态码与资源命名保持复数名词加层级。底部提示:幂等性是重试与去重设计的地基 图 2:左半张是方法语义谱系,右半张是 API 设计的三步决策路径。

API 设计的三步决策。

第一步,动作能不能用资源名词表达?「创建订单」是 POST /orders,「取消订单」与其说 POST /cancelOrder,不如建模成 PUT /orders/123/status 或直接 DELETE 一个「履约申请」资源。能用名词加方法表达的,就用标准语义——网关、缓存、监控这些基础设施全都认识它们;只有真正表达不了的动作(如「发起退款审批」这类跨资源流程),才落到动作式端点。

第二步,重复请求会不会出错?会出错的操作只有两条路:选幂等方法承载(能整量替换就别用增量),或者给请求配幂等键——客户端生成唯一 ID,服务端用该 ID 去重,重复到达的请求直接返回首次结果。支付、下单、库存扣减这些场景,幂等键是标配,不靠客户端自觉。

第三步,状态码与命名收口。状态码用语义说话:创建成功返回 201 而不是一律 200,删除成功无返回体用 204,参数不合法 400,资源不存在 404,状态冲突(如重复创建唯一资源)409。资源命名用复数名词加层级:/users/123/orders,动词交给方法去表达。

常见误区。

一是 POST 包打天下:所有接口都 POST,把缓存、安全重试、语义监控的红利全部放弃。二是把 PATCH 当幂等用:增量修改默认不幂等,超时重试可能把「加一」执行成「加二」。三是把动词塞进 URL 又叠上错误的方法:POST /orders/123/delete 这种写法,方法和路径的语义打架,出问题时排查成本翻倍。

落到日常:评审 API 设计稿时,先问三个问题——这个动作用对方法了吗?这个操作幂等吗、不幂等靠什么兜底?状态码说人话了吗?三问过完,大部分设计味道就没了。你在项目里见过最别扭的 API 设计是什么样?是方法乱用还是状态码乱飞?欢迎分享。