你写的后端代码,最终是要”被别人调用”的——可能是前端页面、可能是另一个服务、可能是手机 App。这个”调用方和被调用方之间的约定”,就是 API(Application Programming Interface,应用程序编程接口)。而今天最主流的 API 风格,叫 REST,它建立在 HTTP 协议之上。
很多新手写接口时很随意:所有操作都用 POST、路径乱起名、返回码永远 200。结果前端同学拿到接口一脸懵,联调天天吵架。这一篇我们建立 API 设计的”第一性原理”:什么是 REST、HTTP 方法怎么用才对、状态码到底代表什么。
API 到底是什么
打个比方:餐厅里你(顾客)看不到后厨怎么炒菜,但你能通过”菜单 + 服务员”点到菜。API 就是那个”菜单”——它告诉你”我能提供哪些能力、你要传什么参数、我会返回什么”。你不需要知道后端数据库怎么存、逻辑怎么算,只要按约定发请求,就能拿到结果。
一个典型的 REST API 请求长这样:
GET /api/users/123 HTTP/1.1
Host: api.example.com
Authorization: Bearer xxxx
它表达的是:“请给我 id 为 123 的用户信息”。后端处理后返回 JSON 数据。这就是 API 的日常形态。
什么是 REST
REST(Representational State Transfer,表现层状态转移)是一套设计风格(不是标准、不是协议)。它有几个核心约束,记住这几点就够入门:
- 资源由 URL 唯一标识:每个”东西”(用户、订单、文章)都是一个资源,用路径表示,比如
/users/123。 - 用 HTTP 方法表达”动作”:对同一个资源,GET 是查、POST 是增、PUT 是改、DELETE 是删。
- 无状态:每次请求都自带全部信息(比如身份令牌),服务器不”记着”上一次你是谁。这样服务才能轻松横向扩展。
- 返回统一的数据格式:通常是 JSON,前后端都好解析。
符合这些约束的 API,就叫”RESTful API”。它最大的好处是直观——看 URL 和方法,就知道在干什么。
HTTP 方法:别再全用 POST 了
这是新手最爱踩的坑。HTTP 早就定义好了一套”语义动词”,REST 把它们映射到”增删改查”:
| 方法 | 语义 | 典型场景 | 是否幂等 |
|---|---|---|---|
GET | 查询,不修改数据 | 获取用户列表、详情 | 是 |
POST | 新建资源 | 注册用户、提交订单 | 否 |
PUT | 整体替换资源 | 更新用户全部信息 | 是 |
PATCH | 部分更新资源 | 只改用户昵称 | 否 |
DELETE | 删除资源 | 注销账号 | 是 |
几个容易混的点:
- 幂等的意思是”多次调用效果一样”。GET 查一百次还是那个数据,所以幂等;POST 提交一百次可能建一百个订单,所以不幂等。理解幂等对”重试安全”很重要——网络抖动时,幂等接口可以放心重试。
- PUT vs PATCH:PUT 是”把整个资源换成新的”(没传的字段会被清空),PATCH 是”只改你传的字段”。前端部分更新用 PATCH 更友好。
- GET 不能有请求体:查询参数都放 URL(
?id=1)或路径里,别把复杂查询塞进 GET 的 body(很多网关、缓存不认)。
正确示例:
GET /users # 查列表
GET /users/123 # 查详情
POST /users # 新建用户
PUT /users/123 # 整体更新 123
PATCH /users/123 # 部分更新 123
DELETE /users/123 # 删除 123
状态码:让”结果”自己说话
HTTP 状态码是服务器告诉客户端”这次请求怎么样了”的标准化数字。别总返回 200 然后在 body 里写 {"code":500,"msg":"失败"}——那是把 HTTP 协议的能力浪费了。常用状态码分五类:
- 2xx 成功:
200 OK(通用成功)、201 Created(创建成功,常配合 POST)、204 No Content(成功但无返回体,如删除)。 - 3xx 重定向:
301/302跳转,API 里较少用。 - 4xx 客户端错误:
400 Bad Request(参数错)、401 Unauthorized(未登录/无身份)、403 Forbidden(已登录但没权限)、404 Not Found(资源不存在)、409 Conflict(冲突,如重复创建)、422 Unprocessable Entity(参数格式对但语义错)。 - 5xx 服务端错误:
500 Internal Server Error(代码崩了)、502 Bad Gateway(上游挂了)、503 Service Unavailable(过载/维护)。
关键认知:4xx 是客户端的锅(参数错、没登录),5xx 是服务端的锅(代码 bug、依赖挂了)。这个区分让前端和运维一眼就能甩锅定位问题。
一个设计良好的接口长什么样
综合上面三点,一个”查用户”的接口应该是:
请求:GET /api/users/123
响应:200 OK
{
"id": 123,
"name": "小明",
"age": 18
}
而”创建用户失败因为没填名字”应该是:
请求:POST /api/users (body 缺少 name)
响应:400 Bad Request
{
"error": "name 不能为空"
}
注意:状态码是 400(客户端参数错),不是 200 包个错误码。这样任何 HTTP 客户端、监控、网关都能直接基于状态码做判断。
常见新手坑
- 所有接口都用 POST:丢失了 HTTP 方法的语义,缓存、幂等、网关规则全失效。能用 GET 查的就用 GET。
- 永远返回 200:把错误塞进 body,导致监控、重试逻辑无法基于状态码工作,联调时极难排查。
- 把动词当资源:
/getUser、/deleteUser这种路径是”RPC 风格”,不是 REST。应改成/users/{id}配 GET/DELETE。 - 混淆 401 和 403:401 是”你是谁?没凭证”;403 是”我知道你是谁,但你没权限”。语义不同,前端提示也不同。
- GET 请求带敏感 body:查询参数在 URL 里,会被日志、浏览器历史记下来,密码、token 绝不能放 GET。
实战:为一个”待办事项”设计 REST 接口
假设要做任务管理,资源是 todos,合理的接口集应该是:
GET /todos # 列表(支持 ?status=done&page=1)
GET /todos/1 # 详情
POST /todos # 新建(body: {title, content})
PUT /todos/1 # 整体改
PATCH /todos/1 # 改状态(body: {status:"done"})
DELETE /todos/1 # 删除
这套设计的好处:前端同学看一眼就知道每个接口干嘛、用什么方法、传什么;后端也容易按资源拆分模块。这就是 REST 带来的”约定优于配置”。
新手怎么把 API 基础打牢
API 设计是后端工程师的”门面”,设计烂了前端天天来找你。建议每天看一个公开 API(比如 GitHub API、天气预报 API),对着它的 URL 和方法,思考”它为什么这么设计”。重点是强迫自己遵守语义:查就用 GET、建就用 POST、改就用 PUT/PATCH、删就用 DELETE,别偷懒全 POST。
另一个心法:状态码是你的免费信号系统。它不占你一行业务代码,却能让网关、监控、前端、运维都受益。从今天起,错误就返回对应的 4xx/5xx,成功就返回对应的 2xx,别再 200 包一切。
还有,理解”无状态”对后端扩展的意义。如果你的服务”记着”每个用户的上一次请求状态(比如存在服务器内存里),那这个服务就不能随便加机器——因为用户下次可能落到另一台机器上,状态就丢了。REST 要求每次请求自带凭证,正是为了让你能水平扩展。
小测验:看看你掌握了没
- 问题一:POST 和 PUT 在”幂等”上有什么区别?答案:POST 不幂等(多次可能建多个资源),PUT 幂等(多次整体替换结果一样)。
- 问题二:401 和 403 分别是什么意思?答案:401 是未认证(没身份),403 是已认证但无权限。
- 问题三:为什么查询接口不该用 POST?答案:GET 可被缓存、幂等、参数在 URL;POST 查数据会失去这些特性,也不符合 REST 语义。
这一篇你该记住的
- API 是”调用方与被调用方的约定”;REST 是基于 HTTP 的设计风格。
- REST 核心:资源用 URL 标识、用 HTTP 方法表动作、无状态、返回 JSON。
- 方法语义:GET 查、POST 建、PUT 整体改、PATCH 部分改、DELETE 删;注意幂等性。
- 状态码是免费信号:2xx 成功、4xx 客户端错、5xx 服务端错,别总返回 200。
- 设计良好 = “看 URL + 方法就知道在干嘛”,约定优于配置。
下一篇我们讲 URL 与资源设计:怎么给资源起名、怎么设计嵌套、怎么处理过滤排序分页,把”能跑”提升到”好看又好用”。