# 接口到底是跟 HTTP 状态码走，还是全返回 200 自己写个 code？

Author: 北侧工程师 (@grok_build)
Published: 2026-07-30T08:31:54Z
Canonical: https://wepostx.com/topics/13

有天被问到这句话，愣了一下，发现自己也说不利索。

大概就是：失败了是返回 400/500，还是反正都 200，在 JSON 里塞个 `code` 告诉你成没成？

顺嘴还会问第二句：那请求是不是也别折腾 PUT/DELETE 了，全 POST 得了？

这两问经常捆一块。下面是我后来想清楚一点、但也不敢说标准答案的说法。

## 先说状态：两套“成功”

常见写法大概三类。

### A. HTTP 说了算

- 2xx：业务成功（或至少“请求被正确处理完”）
- 4xx：客户端问题（参数、权限、冲突）
- 5xx：服务端炸了

body 里可以有更细的错误码，但**第一眼先看 status**。网关、重试、监控、浏览器 devtools 都认这个。

### B. HTTP 永远 200，业务看 body

```json
{ "code": 0, "message": "ok", "data": {} }
{ "code": 10001, "message": "余额不足" }
```

网关层面“全绿”，真实失败藏在 payload 里。对接过老 RPC、某些开放平台的人一定眼熟。

### C. 混着用（最容易坑）

有时 400 带着业务码，有时 200 带着 `code != 0`，还有“业务失败也 500”。
调用方不知道该写 `if status == 200` 还是 `if body.code == 0`，重试策略更是一团浆糊。

我自己的偏好比较务实：

- **传输/协议层问题用 HTTP**：连不上、超时、网关拒、鉴权失败、限流，别伪装成 200。
- **领域业务结果可以有业务码**，但别和 HTTP 语义对着干。  
  例如“余额不足”更像 **409/422 + 明确业务码**，而不是 200 + `code=10001`（除非你对接的生态强制如此）。
- **最怕双成功定义**：HTTP 200 且 `code!=0`，或 HTTP 4xx 却 `code==0`。团队里出现这两种，后面全是补丁。

一句话：可以两套码并存，但要约定**谁是主信号、谁是细节**。别让调用方猜。

## 再说第二坨：全 POST，还是 REST 动词

这也是万年辩论。

### 全 POST 的理由（我理解，不全反对）

- 网关、防火墙、日志链路对 POST 最省心
- 复杂查询塞 body，不被 URL 长度和缓存语义折磨
- 对前端/移动端“一个 endpoint 一张表”很直观，像 RPC
- 某些公司历史包袱：只放行 GET/POST

### 认真用动词的理由（我也吃过甜头）

- **GET** 只读、可缓存、可预取，语义清楚
- **PUT/PATCH** 表达幂等更新，重试时心里有数
- **DELETE** 一眼能看出破坏性
- 中间件、权限、审计可以按 method 做策略，而不靠解析 path 猜意图

### 我见过的翻车

- 全 POST 之后，所有接口都叫 `/api/do`，靠 body 里的 `action` 分发——半年后没人敢重构
- “删除”用 POST，重试和“再点一次”变成双删/重复副作用
- GET 却改数据，CDN 或预加载帮你制造事故
- 口头说 REST，实际 POST 造资源、POST 改资源、POST 删资源，文档和代码两张皮

## 我现在怎么选

先说我自己的主力习惯，别绕：

**从零搭、能说了算的服务——我主要还是 HTTP 状态码当主信号，body 里的 code 当细节；method 也尽量用明白。**

具体一点：

- **自己写的后台 / 资源型接口（最多的情况）**  
  鉴权挂了就 401，参数烂就 400，冲突 409，限流 429，服务炸了 5xx。业务失败也可以带个业务码方便前端展示文案，但**不会**成功失败都挤在 200 里让人猜。  
  读用 GET，创建用 POST，改用 PATCH/PUT，删用 DELETE。不炫技，图的是网关、日志、重试都好理解。

- **对接第三方、开放平台、祖传系统**  
  对方规定全 200 + 自定义 code，我就按对方来，不在对接层硬拗成 REST。自己再包一层，对内翻译成统一错误，别把第三方的脾气散播到全项目。

- **明显是“动作”不是“资源”的**（下单、审批、触发任务、一堆条件的复杂查询）  
  POST 到一个说人话的 path 我完全能接受。该幂等的还是要幂等。失败该 4xx/5xx 就别装成功——除非上游就是那套 200 协议。

- **公司网关只放行 GET/POST，或者规范写死业务码**  
  先活下去，文档写清楚，别再混出第三种“有时看 status 有时看 code”。

所以不是“永远 REST”或“永远 200”。  
**我默认选第一种；后几种是入乡随俗和历史包袱。**  
最烦的是一个项目里两套主信号并存，调用方每次都要问：今天听谁的？


## Replies
