RESTful API 基础归纳总结

说实话,很多做SDK的同学对RESTful API的理解还停留在“就是叫URL发请求”的阶段。嗯,没错,但不够。我自己在早期设计一个支付SDK时,就因为在资源命名上偷了懒,后来兼容性改到想哭。今天咱们把这块掰开揉碎了看看。

REST 的核心原则

REST不是协议,是架构风格。它绕着资源转,每个东西都有一个URI,通过统一接口操作。我个人习惯用五个词记住:

  • 资源 – 一切都抽象成资源,比如用户、订单
  • URI – 每个资源唯一的地址
  • 表示 – JSON、XML等形式,客户端和服务端商量好就行
  • 无状态 – 服务端不存客户端上下文,请求自包含
  • 超媒体驱动 – 响应里带着链接,告诉你下一步能干嘛

你想想看,这里最关键的是无状态。我在一个高并发项目中,就因为服务端偷偷塞了session,导致水平扩展时各种诡异超时。后来痛下决心全改成自包含,世界清净了。

HTTP 方法的设计

RESTful API 的“统一接口”靠的就是 HTTP 方法。记住下面这张表就够了:

方法作用幂等安全
GET读取资源是是(不改变状态)
POST创建资源否否
PUT整体更新/替换是否
PATCH部分更新不一定否
DELETE删除资源是否
幂等性是个大坑。我曾经因为 PATCH 没做幂等处理,客户端重试时把订单金额改错了两次。教训很深——设计时就要把“重试安全”刻在脑子里。

为什么要区分 PUT 和 PATCH?举个例子:更新用户头像,用 PUT 就得把整个用户对象全传过来,明显不合理。PATCH 只传要改的字段,省带宽。不过注意,PATCH 的幂等性需要你自己保障。

状态码的选择

状态码别乱用。我见过不少 API 无论成功失败都返回 200,然后在 body 里放 code 字段判断。这其实是在浪费 HTTP 的语义能力。核心原则:

  • 2xx – 成功。200 通用成功,201 创建成功(POST),204 删除成功无内容。
  • 3xx – 重定向。很少用,但资源移动时该用 301/302。
  • 4xx – 客户端错误。400 参数错误,401 未认证,403 无权限,404 资源不存在,409 冲突(比如重复创建)。
  • 5xx – 服务端错误。500 内部错误,502 网关超时,503 服务不可用。
千万不要把业务错误(比如余额不足)也用 200 包一层返回。那样客户端解析时还要看 code,破坏了 HTTP 的承诺。正确做法:用 422 Unprocessable Entity,在 body 里给具体原因。

资源 URI 的设计

URI 是给人看的,也是给机器用的。我常用的风格:

  • 使用名词复数 – /users、/orders,动词用 HTTP 方法代替。
  • 层级关系用路径 – /users/123/orders/456,直观清晰。
  • 过滤、排序、分页用 query – ?status=active&page=1&size=20。
  • 避免动词 – 不要写 /getUser,用 GET /users/123。
# 好的例子
GET   /users/123                     # 获取用户
POST  /users                         # 新建用户
PUT   /users/123                     # 替换用户
PATCH /users/123                     # 部分更新
DELETE /users/123                    # 删除用户

# 坏的例子
GET   /getUser?id=123                # 动词 + query 参数,不纯粹
POST  /createUser                    # 该用 /users + POST
POST  /users/123/delete              # 该用 DELETE /users/123

为什么这么设计?因为一旦形成惯例,SDK 的代码生成器就能自动根据 /users/{id}/orders 生成对象层级。我在一个多端项目中,这样统一后前端和后端联调效率翻了一倍。

HATEOAS 与版本管理

HATEOAS(超媒体作为应用状态引擎)是 REST 的终极形态。简单说:API 的响应里包含链接,告诉客户端下一步能做什么。比如:

{
  "id": 123,
  "name": "Alice",
  "links": [
    { "rel": "self", "href": "/users/123" },
    { "rel": "orders", "href": "/users/123/orders" },
    { "rel": "update", "method": "PUT", "href": "/users/123" }
  ]
}

客户端不用硬编码 URL,跟着链接走就行。我个人觉得在 SDK 设计里,HATEOAS 的实用价值在于:服务端可以灵活调整资源关系,而 SDK 依然可以稳健。但现实是很多团队嫌麻烦,只给了静态文档。

版本管理呢?两种主流方式:

  • URI 里放版本号 – /v1/users/123,最简单,也最常用。
  • 请求头协商 – Accept: application/vnd.yourapp.v1+json,更干净但复杂度高。
建议初期就用 URL 版本。别一开始就搞头协商,除非你的 API 需要支持多种表示格式。我见过一个团队用头协商,但前端缓存策略没跟上,导致新旧版本混用,排查到崩溃。

好了,上面这些构成了 RESTful API 的核心骨骼。下面这张图可以帮你把各要素串起来。

RESTful API 核心架构 客户端 URI + HTTP 方法 资源 状态码 HATEOAS 链接 版本管理 无状态、资源导向、统一接口 —— 三者缺一不可 版本管理保证向后兼容,HATEOAS 则让 API 具备自描述能力

图里每个节点你都可以和我刚才讲的内容一一对应。客户端发请求,经过 URI + HTTP 方法到达资源,然后返回状态码,响应里可以带 HATEOAS 链接,最后所有东西都要被版本管理兜底。这个结构跑起来后,你的 SDK 设计就稳了一大半。