2、RESTful API 设计原则:资源导向、无状态性、统一接口、HATEOAS 概念

聊到消息接口,RESTful API 是绕不开的话题。我做了这么多年通信架构,见过太多把 REST 用成 RPC 的项目。说白了,很多人只是把 HTTP 当成了传输管道,根本没理解 REST 的精髓。

今天我就把这四个核心原则掰开揉碎了讲。你理解透了,设计出来的接口会清爽很多。

2.1 资源导向:把一切抽象为资源

REST 的核心思想是什么?是把系统中的一切视为「资源」。用户是资源,订单是资源,文章也是资源。每个资源都有一个唯一的 URI 来标识。

我个人习惯这样设计 URI:

# 好的设计
GET    /users          # 获取用户列表
GET    /users/123      # 获取单个用户
POST   /users          # 创建用户
PUT    /users/123      # 更新用户
DELETE /users/123      # 删除用户

# 糟糕的设计
GET    /getUser?id=123
POST   /createUser
POST   /deleteUser?id=123

看出区别了吗?好的设计用名词表示资源,用 HTTP 方法表示操作。糟糕的设计把动词塞进了 URI 里。我在项目中遇到过团队把接口写成 /api/deleteUserById 这种风格,后来维护起来简直噩梦——接口数量爆炸,命名还不统一。

核心原则:URI 只表示资源,操作由 HTTP 方法决定。永远不要在 URI 里出现动词。

2.2 无状态性:每次请求都是独立的

无状态性是什么意思?就是服务器不保存客户端的状态。每次请求都包含所有必要的信息,服务器不需要记住你之前做过什么。

你想想看,这有什么好处?

  • 水平扩展容易——任何服务器都能处理任何请求
  • 故障恢复简单——挂了一台,换一台照样干活
  • 缓存友好——请求独立,缓存策略清晰

嗯,这里要注意。无状态不是说应用不能有状态,而是说服务器不保存会话状态。状态可以放在客户端,比如用 Token 或 JWT。

// 有状态的请求(错误示范)
GET /api/orders
// 服务器需要知道当前用户是谁,依赖之前的登录状态

// 无状态的请求(正确示范)
GET /api/orders
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
// 每次请求都带上认证信息,服务器无需记忆

我曾经踩过一个坑。早期做电商系统,把用户购物车信息存在服务器 Session 里。结果用户量一上来,服务器扛不住,加机器又因为 Session 不共享导致用户数据错乱。后来改成无状态设计,把购物车信息存在客户端,每次请求都带上,问题就解决了。

避坑指南:我曾经在无状态接口里偷偷用了服务端缓存来存用户状态,结果上线后用户数据串得一塌糊涂。无状态就是无状态,别耍小聪明。

2.3 统一接口:用标准化的方式操作资源

统一接口的意思是,所有资源都通过相同的接口规范来操作。HTTP 方法就是这套规范的核心。

HTTP 方法 操作 幂等 安全
GET 获取资源 是 是
POST 创建资源 否 否
PUT 完整更新资源 是 否
PATCH 部分更新资源 否 否
DELETE 删除资源 是 否

统一接口还要求使用标准的 HTTP 状态码。200 表示成功,201 表示创建成功,404 表示资源不存在,500 表示服务器内部错误。别自己发明状态码,也别把错误信息全塞在 200 里。

小技巧:我习惯在响应体里统一返回 { "code": 0, "message": "success", "data": {...} } 这种结构。HTTP 状态码管传输层,业务状态码管应用层,两者不冲突。

2.4 HATEOAS:让 API 自描述

HATEOAS 全称是 Hypermedia as the Engine of Application State。名字很唬人,说白了就是:API 返回的数据里,应该包含下一步能做什么的链接。

举个例子你就明白了:

// 传统 API 返回
{
  "orderId": 123,
  "status": "pending",
  "amount": 99.00
}

// 带 HATEOAS 的返回
{
  "orderId": 123,
  "status": "pending",
  "amount": 99.00,
  "links": [
    { "rel": "self", "href": "/orders/123" },
    { "rel": "pay", "href": "/orders/123/payments", "method": "POST" },
    { "rel": "cancel", "href": "/orders/123", "method": "DELETE" }
  ]
}

看到区别了吗?传统 API 返回的是死数据,客户端得自己硬编码下一步逻辑。HATEOAS 把「能做什么」也告诉你了。客户端只需要跟着链接走,不需要提前知道所有接口地址。

我个人觉得,HATEOAS 在实际项目中用得不多,但它的思想很有价值。它让 API 变得可发现、可演化。你想想看,如果哪天接口地址变了,只要链接对,客户端根本不需要改代码。

我的建议:不用追求完全的 HATEOAS 实现,但可以在关键资源上加上 links 字段。比如订单详情里带上支付链接,用户信息里带上修改密码的链接。这样 API 的可用性会好很多。

2.5 知识体系总览

下面这张图把四个原则的关系梳理清楚了。你看一眼就能把握整体脉络。

RESTful API 设计原则 资源导向 一切皆资源 URI 用名词,不用动词 HTTP 方法表示操作 无状态性 请求独立,服务器不记忆 状态放在客户端 易于水平扩展 统一接口 标准化 HTTP 方法 统一状态码规范 幂等性保证 HATEOAS API 自描述 返回中包含链接 客户端可发现下一步 四个原则相互支撑,共同构成 RESTful 架构风格

这四个原则不是孤立的。资源导向决定了你用什么来抽象系统,无状态性决定了请求怎么交互,统一接口规范了操作方式,HATEOAS 让 API 变得智能。把它们结合起来,你就能设计出真正符合 REST 精神的接口。

好了,这一章就到这里。记住,设计 RESTful API 不是套模板,而是理解背后的思想。下次你写接口的时候,多想想这四个原则,代码质量会提升不少。