在微服务架构中,API 是服务间通信和前后端交互的核心。RESTful API 作为一种基于 HTTP 协议的设计规范,通过 “资源为中心” 的思想和语义化的操作,让接口具备一致性、可读性和可扩展性。本文结合实战场景,详细讲解 RESTful API 的设计规范,包含 URI 命名、HTTP 方法使用、状态码、响应格式等关键内容,并融入具体示例帮助理解。
一、RESTful API 核心原则
RESTful API 的设计围绕以下核心原则展开,这些原则是规范的基础:
-
以资源为中心
所有接口设计都围绕 “资源”(如用户、商品、订单)展开,资源通过 URI(统一资源标识符)唯一标识,而非围绕 “操作”(如 “获取用户”“删除订单”)。 -
HTTP 方法语义化
利用 HTTP 的方法(GET、POST、PUT、PATCH、DELETE)表达对资源的操作,而非在 URI 中使用动词(如/getUser
、/deleteOrder
)。 -
无状态通信
服务器不存储客户端状态,每次请求必须包含所有必要信息(如 Token、参数),便于服务水平扩展。 -
统一接口
接口格式、响应结构、状态码使用保持一致,降低开发者学习和使用成本。
二、URI 设计规范:资源的唯一标识
URI(Uniform Resource Identifier)是资源的唯一地址,其设计直接影响 API 的可读性和一致性。
1. 基础规则
- 使用小写字母:避免大小写混合(如
/Api/V1/Users
是错误的),统一小写(/api/v1/users
)。 - 连字符(-)分隔多单词:如
/order-details
(订单详情),不使用下划线(_
)或驼峰(orderDetails
)。 - 不包含动词:URI 中只体现资源,操作通过 HTTP 方法表达(如
/users
而非/getUsers
)。 - 版本控制:在 URI 中包含版本(如
/api/v1/users
),便于迭代升级(后续可扩展v2
版本,不影响旧版本)。
2. 资源路径设计
(1)资源集合与单个资源
- 资源集合用复数名词表示:
/api/v1/users
(用户列表)、/api/v1/goods
(商品列表)。 - 单个资源用 “集合 + ID” 表示:
/api/v1/users/1
(ID 为 1 的用户)、/api/v1/goods/1001
(ID 为 1001 的商品)。
资源 | 描述 |
---|---|
/users | 所有用户(集合) |
/users/1 | ID 为 1 的单个用户 |
/goods | 所有商品(集合) |
/goods/1001 | ID 为 1001 的单个商品 |
(2)资源间关系:体现嵌套层级
当资源存在从属关系时,用子路径表示。例如:
GET /api/v1/users/1/orders
:用户 1 的所有订单(订单从属于用户)。GET /api/v1/orders/10/items
:订单 10 包含的所有商品条目(条目从属于订单)。
注意:避免过深嵌套(如/users/1/orders/10/items/5
),可通过查询参数简化。例如,查询订单 10 的条目 5,可设计为/api/v1/order-items/5?orderId=10
。
(3)反例与正例对比
不规范 URI | 问题说明 | 规范 URI |
---|---|---|
/api/getUser?id=1 | URI 包含动词get | /api/v1/users/1 |
/api/user/delete/1 | URI 包含动词delete | /api/v1/users/1 (用 DELETE 方法) |
/Api/V1/Users/1 | 大小写混合 | /api/v1/users/1 |
/api/v1/user_orders/1 | 使用下划线分隔 | /api/v1/user-orders/1 |
/api/v1/users/1/orders/10/items | 嵌套过深 | /api/v1/order-items?orderId=10 |
三、HTTP 方法与资源操作的对应关系
RESTful API 通过 HTTP 方法表达对资源的操作,每种方法有明确的语义和适用场景:
HTTP 方法 | 操作类型 | 幂等性 * | 适用场景 | 示例 URI | 示例描述 |
---|---|---|---|---|---|
GET | 查询资源 | 是 | 获取资源列表或单个资源 | /api/v1/users | 查询所有用户 |
/api/v1/users/1 | 查询 ID 为 1 的用户 | ||||
POST | 创建资源 | 否 | 新建资源(服务器生成 ID) | /api/v1/users | 创建新用户 |
PUT | 全量更新资源 | 是 | 替换资源的所有字段(需提供完整资源信息) | /api/v1/users/1 | 完整更新用户 1 的信息(如替换所有字段) |
PATCH | 部分更新资源 | 否 | 仅更新资源的部分字段 | /api/v1/users/1 | 更新用户 1 的昵称(其他字段不变) |
DELETE | 删除资源 | 是 | 删除指定资源 | /api/v1/users/1 | 删除 ID 为 1 的用户 |
* 幂等性:多次执行相同操作,结果一致(如 GET 多次查询结果相同,PUT 多次更新结果相同;POST 创建资源多次会生成多个记录,因此非幂等)。
实战示例:用户资源的完整接口
# 1. 查询用户列表
GET /api/v1/users
# 2. 查询单个用户
GET /api/v1/users/1
# 3. 创建用户(服务器生成ID)
POST /api/v1/users
# 4. 全量更新用户(需传递所有必填字段)
PUT /api/v1/users/1
# 5. 部分更新用户(仅传递需修改的字段)
PATCH /api/v1/users/1
# 6. 删除用户
DELETE /api/v1/users/1
如何区分 GET 和 POST?
GET
请求
🔹 适用场景:
- 获取列表(如购物车列表)
- 查询单个资源
- 过滤、排序、分页等操作
POST
请求
🔹 适用场景:
- 创建新资源(如添加购物车条目)
- 提交用户输入的数据
- 操作会引起服务端状态变化
判断标准 | 使用 GET | 使用 POST |
---|---|---|
是否要修改服务器状态? | ❌ 不会修改 | ✅ 会修改 |
是否要上传大量/敏感数据? | ❌ 不适合 | ✅ 推荐 |
是否需要幂等性? | ✅ 需要 | ❌ 不需要 |
是否是“读取”操作? | ✅ 是 | ❌ 否 |
是否是“创建”操作? | ❌ 否 | ✅ 是 |
总结一句话:
如果你是在获取数据且不修改服务器状态 → 用
GET
;<br>如果你是在创建、更新或删除资源 → 用POST
/PUT
/DELETE
。
这样设计出的接口才符合 RESTful 规范,也更容易维护和理解。
四、请求体设计规范
请求体(Request Body)用于传递资源的创建、更新信息,推荐使用JSON 格式,并遵循以下规范:
1. 字段命名与格式
- 统一命名风格:选择驼峰命名(
camelCase
)或蛇形命名(snake_case
),并保持全局一致(推荐蛇形命名,更符合数据库字段风格)。 - 避免冗余字段:不传递与资源无关的信息(如无需在创建用户时传递
update_time
,由服务器生成)。 - 嵌套结构清晰:复杂资源可使用嵌套 JSON(如用户的地址信息)。
2. 实战示例
(1)创建用户(POST /api/v1/users)
{
"username": "zhangsan",
"email": "zhangsan@example.com",
"age": 25,
"address": { // 嵌套结构
"province": "beijing",
"city": "beijing"
}
}
(2)部分更新用户(PATCH /api/v1/users/1)
{
"age": 26, // 仅更新年龄字段
"email": "new-zhangsan@example.com" // 同时更新邮箱
}
五、响应体设计规范
响应体(Response Body)需统一格式,包含状态标识、数据、错误信息(按需返回),便于客户端解析。
1. 通用结构
响应体应包含以下核心字段(JSON 格式):
字段名 | 类型 | 说明 | 出现场景 |
---|---|---|---|
code | 整数 | 业务状态码(通常与 HTTP 状态码一致) | 所有响应 |
message | 字符串 | 操作结果描述(如 “成功”“参数错误”) | 所有响应 |
data | 任意 | 业务数据(查询 / 创建 / 更新的资源信息) | 成功响应(2xx) |
error | 字符串 | 错误详情(如参数校验失败的具体原因) | 失败响应(4xx/5xx) |
timestamp | 整数 | 响应时间戳(毫秒) | 可选,便于问题排查 |
2. 成功响应示例
(1)查询单个资源(GET /api/v1/users/1)
{
"code": 200,
"message": "success",
"timestamp": 1690000000000,
"data": {
"id": 1,
"username": "zhangsan",
"email": "zhangsan@example.com",
"age": 25,
"created_at": "2023-01-01T00:00:00Z"
}
}
(2)创建资源(POST /api/v1/users)
{
"code": 201, // 对应HTTP状态码201(创建成功)
"message": "created",
"timestamp": 1690000001000,
"data": {
"id": 2, // 服务器生成的新资源ID
"username": "lisi",
"created_at": "2023-08-01T00:00:00Z"
}
}
(3)删除资源(DELETE /api/v1/users/1)
{
"code": 204, // 对应HTTP状态码204(无内容)
"message": "deleted",
"timestamp": 1690000002000
// 无data字段(删除成功无需返回资源)
}
3. 失败响应示例
(1)参数错误(400 Bad Request)
{
"code": 400,
"message": "参数错误",
"timestamp": 1690000003000,
"error": "email格式不正确(应为xxx@xx.com)"
}
(2)资源不存在(404 Not Found)
{
"code": 404,
"message": "资源不存在",
"timestamp": 1690000004000,
"error": "用户ID=999不存在"
}
(3)服务器内部错误(500 Internal Server Error)
{
"code": 500,
"message": "服务器内部错误",
"timestamp": 1690000005000,
"error": "数据库连接超时" // 生产环境可简化为“系统繁忙,请稍后再试”
}
六、HTTP 状态码的正确使用
HTTP 状态码是 RESTful API 的 “语言”,客户端可通过状态码快速判断请求结果,无需解析响应体。以下是常用状态码及适用场景:
1. 2xx(成功)
状态码 | 含义 | 适用场景 |
---|---|---|
200 | OK(成功) | GET 查询成功、PUT/PATCH 更新成功 |
201 | Created(创建成功) | POST 创建资源成功(如新建用户、订单) |
204 | No Content(无内容) | DELETE 删除成功、无需返回数据的 PUT 请求 |
2. 4xx(客户端错误)
状态码 | 含义 | 适用场景 |
---|---|---|
400 | Bad Request(请求错误) | 参数格式错误(如手机号位数不正确) |
401 | Unauthorized(未认证) | 未携带 Token、Token 无效或过期 |
403 | Forbidden(权限不足) | 已认证但无操作权限(如普通用户删除管理员) |
404 | Not Found(资源不存在) | 请求 URI 错误(如/api/v1/usrs )或资源 ID 不存在 |
405 | Method Not Allowed | 请求方法不支持(如对/users/1 用 POST) |
409 | Conflict(资源冲突) | 创建用户时用户名已存在、修改资源版本冲突 |
422 | Unprocessable Entity | 参数校验失败(如年龄为负数) |
3. 5xx(服务器错误)
状态码 | 含义 | 适用场景 |
---|---|---|
500 | Internal Server Error | 服务器内部错误(如代码 Bug、数据库连接失败) |
503 | Service Unavailable | 服务不可用(如过载、维护中) |
注意事项
- 状态码与业务一致:如 “资源不存在” 必须返回 404,而非 200 + 错误消息(客户端可能依赖状态码处理逻辑)。
- 避免滥用 500:500 应仅用于服务器未预期的错误,客户端可修复的错误(如参数错误)应返回 4xx。
七、分页、排序与过滤的设计
对于资源列表查询(如GET /api/v1/users
),需支持分页、排序、过滤功能,通过查询参数(Query Parameters) 实现。
1. 分页参数
参数名 | 含义 | 示例 |
---|---|---|
page | 当前页码(从 1 开始) | ?page=1 (第一页) |
size | 每页条数 | ?page=1&size=10 (每页 10 条,第一页) |
响应示例(GET /api/v1/users?page=1&size=2):
{
"code": 200,
"message": "success",
"data": {
"items": [ // 当前页数据
{"id": 1, "username": "zhangsan"},
{"id": 2, "username": "lisi"}
],
"total": 100, // 总条数
"page": 1, // 当前页
"size": 2, // 每页条数
"pages": 50 // 总页数
}
}
2. 排序参数
参数名 | 含义 | 示例 |
---|---|---|
sort | 排序字段及方向(字段,方向 ) | ?sort=age,asc (按年龄升序) |
?sort=create_time,desc (按创建时间降序) |
3. 过滤参数
根据资源字段定义过滤条件,常用方式:
过滤类型 | 参数示例 | 含义 |
---|---|---|
等值过滤 | ?status=active | 查询状态为 “active” 的用户 |
范围过滤 | ?age_min=18&age_max=30 | 查询年龄 18-30 的用户 |
模糊搜索 | ?username_like=zhang | 查询用户名包含 “zhang” 的用户 |
多值过滤 | ?ids=1,2,3 | 查询 ID 为 1、2、3 的用户 |
综合示例
查询 “第 2 页、每页 10 条、按创建时间降序、状态为 active 的用户”:
GET /api/v1/users?page=2&size=10&sort=create_time,desc&status=active
八、版本控制策略
API 迭代过程中,需保证旧版本兼容性,常用的版本控制方式有以下 3 种:
1. URI 路径包含版本(推荐)
在 URI 中显式包含版本号(如v1
、v2
),清晰直观,便于测试和维护:
/api/v1/users // 版本1
/api/v2/users // 版本2(不影响v1的使用)
2. 请求头包含版本
通过Accept
请求头指定版本,不污染 URI,但客户端实现稍复杂:
Accept: application/vnd.example.v1+json // 调用v1版本
Accept: application/vnd.example.v2+json // 调用v2版本
3. 查询参数包含版本
通过version
参数指定版本,不推荐(易被忽略,且不符合 “资源唯一 URI” 原则):
/api/users?version=1 // 不推荐
九、实战:完整的商品 API 设计示例
以电商系统的 “商品” 资源为例,展示符合 RESTful 规范的完整 API 设计:
方法 | URI | 功能描述 | 请求体示例 | 响应体示例(成功) |
---|---|---|---|---|
GET | /api/v1/goods | 查询商品列表 | - | {"code":200,"message":"success","data":{"items":[...],"total":100}} |
GET | /api/v1/goods/1001 | 查询单个商品 | - | {"code":200,"message":"success","data":{"id":1001,"name":"手机","price":3999}} |
POST | /api/v1/goods | 创建商品 | {"name":"电脑","price":5999,"stock":100} | {"code":201,"message":"created","data":{"id":1002,"name":"电脑"}} |
PUT | /api/v1/goods/1001 | 全量更新商品 | {"name":"手机(新款)","price":4999,"stock":50} | {"code":200,"message":"success","data":{"id":1001,"name":"手机(新款)"}} |
PATCH | /api/v1/goods/1001 | 部分更新商品 | {"stock":49} | {"code":200,"message":"success","data":{"id":1001,"stock":49}} |
DELETE | /api/v1/goods/1001 | 删除商品 | - | {"code":204,"message":"deleted"} |
十、总结
RESTful API 设计规范的核心是 “一致性”—— 统一的 URI 命名、HTTP 方法使用、响应格式和状态码,让接口易于理解和使用。在微服务项目中,遵循这些规范能带来以下好处:
- 降低沟通成本:团队成员无需额外文档即可理解接口功能。
- 便于扩展:规范的设计让 API 迭代(如新增字段、版本升级)更平滑。
- 跨团队协作:前端、后端、第三方开发者遵循同一标准,减少适配成本。
实际开发中,可结合框架(如 Spring Boot 的@RestController
、FastAPI)自动生成符合规范的接口,并通过 Swagger 等工具生成 API 文档,进一步提升开发效率。
如果这篇文章对大家有帮助可以点赞关注,你的支持就是我的动力😊!