在 Web 服务架构中,RESTful API作为一种轻量级、可扩展的接口设计风格,通过 HTTP 协议实现资源的标准化访问。本文从核心原则、URL 设计、HTTP 方法应用、状态管理及面试高频问题五个维度,结合工程实践与反例分析,系统解析 RESTful API 的设计规范与最佳实践。
原则 | 定义 | 设计目标 |
---|---|---|
资源导向 | 以资源(Resource)为核心,而非操作(如 “用户” 而非 “获取用户”) | 符合大众认知,提升 API 可读性 |
无状态 | 服务器不存储客户端状态,每次请求需包含所有必要信息 | 简化服务器设计,支持水平扩展 |
统一接口 | 通过 URI、HTTP 方法、媒体类型实现统一交互模式 | 降低学习成本,增强接口一致性 |
可缓存 | 响应需明确标记是否可缓存,减少重复请求 | 提升性能,降低服务器负载 |
客户端 - 服务器 | 分离客户端与服务器职责,客户端负责 UI,服务器负责数据存储 | 独立演化,增强系统模块化 |
分层系统 | 客户端无法区分直接访问服务器还是中间层(如网关) | 支持负载均衡、安全代理等中间件 |
维度 | RESTful API | RPC(如 Dubbo/GraphQL) |
---|---|---|
核心抽象 | 资源(名词) | 操作(动词) |
交互方式 | 基于 HTTP 语义(GET/POST 等) | 自定义协议或 HTTP 包装(如 POST+Action 参数) |
可缓存性 | 天然支持(依赖 HTTP 缓存机制) | 需额外实现缓存逻辑 |
可读性 | 强(URL 自解释) | 弱(依赖文档) |
适用场景 | 跨系统集成(如开放平台) | 内部服务调用(高性能需求) |
使用名词复数:表示资源集合(如/users
而非/user
)。
避免动词:资源操作通过 HTTP 方法表达(如GET /users
而非/getUsers
)。
层级结构:通过 URL 路径表示资源间关系(如/users/{id}/orders
表示用户的订单)。
场景 | 错误示例 | 正确示例 |
---|---|---|
用户资源集合 | /getUsers 、/userList |
/users |
单个用户资源 | /user?id=1 、/getUser/1 |
/users/1 |
用户的订单 | /userOrders?userId=1 |
/users/1/orders |
搜索用户 | /searchUsers?name=xxx |
/users?name=xxx |
# 复杂嵌套(不推荐)
/users/1/orders/123/items/456
# 简化方案(推荐)
/items/456?orderId=123&userId=1
/orders/123
(订单可独立访问)/users/1/orders/123
(订单依赖用户上下文)# 筛选状态为active的用户
GET /users?status=active&role=admin
page
页码,size
每页条数):GET /users?page=2&size=20
{
"data": [...],
"pagination": {
"total": 100,
"page": 2,
"size": 20,
"pages": 5
}
}
sort
参数指定排序字段与方向:# 按创建时间降序,姓名升序
GET /users?sort=createdAt,desc&sort=name,asc
方法 | 操作类型 | 幂等性 | 示例 URL | 描述 |
---|---|---|---|---|
GET | 查询 | 是 | /users |
获取资源集合 |
GET | 查询 | 是 | /users/1 |
获取单个资源 |
POST | 创建 | 否 | /users |
创建新资源(服务器生成 ID) |
PUT | 全量更新 | 是 | /users/1 |
替换资源所有字段 |
PATCH | 部分更新 | 是 | /users/1 |
更新资源部分字段 |
DELETE | 删除 | 是 | /users/1 |
删除指定资源 |
POST /users/1
更新用户(非幂等,应使用 PUT)。状态码 | 含义 | 适用场景 |
---|---|---|
200 | OK(成功) | GET/PUT/PATCH 请求成功并返回数据 |
201 | Created(已创建) | POST 请求成功创建资源(返回 Location 头) |
204 | No Content(无内容) | DELETE 请求成功(无需返回数据) |
状态码 | 含义 | 适用场景 |
---|---|---|
400 | Bad Request | 请求参数错误(如格式不正确) |
401 | Unauthorized | 未认证(如缺少 Token) |
403 | Forbidden | 已认证但无权限 |
404 | Not Found | 资源不存在 |
409 | Conflict | 请求冲突(如创建重复资源) |
429 | Too Many Requests | 请求频率超限(限流场景) |
状态码 | 含义 | 适用场景 |
---|---|---|
500 | Internal Server Error | 服务器未知错误 |
503 | Service Unavailable | 服务暂时不可用(如维护中) |
// POST /users
{
"name": "Alice",
"email": "[email protected]"
}
// PATCH /users/1
{
"email": "[email protected]"
}
{
"code": 200, // 业务码(可选,补充HTTP状态码)
"message": "success", // 提示信息
"data": { ... }, // 业务数据(成功时返回)
"errors": [ ... ] // 错误详情(失败时返回)
}
{
"data": [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"}
],
"pagination": {
"total": 100,
"page": 1,
"size": 20,
"links": {
"next": "/users?page=2&size=20",
"prev": null
}
}
}
{
"id": 1,
"name": "Alice",
"links": [
{"rel": "self", "href": "/users/1"},
{"rel": "orders", "href": "/users/1/orders"},
{"rel": "edit", "href": "/users/1", "method": "PUT"}
]
}
策略 | 实现方式 | 优点 | 缺点 |
---|---|---|---|
URL 路径 | /v1/users 、/v2/users |
直观,易于测试 | URL 冗余,升级需修改路径 |
请求头 | Accept: application/vnd.example.v1+json |
无 URL 污染 | 不直观,客户端实现复杂 |
查询参数 | /users?version=1 |
简单,兼容旧版本 | 易被忽略,缓存困难 |
/v1/users
),平衡可读性与兼容性。Deprecation
响应头标记即将移除的 API(如Deprecation: true
)。v1
和v2
共存)。Q:RESTful API 的 “无状态” 原则是什么?为什么重要?
A:
Q:如何区分 PUT 和 PATCH 方法?
A:
email
字段。Q:如何设计一个支持复杂查询的 RESTful API?
A:
&
连接多个条件(如/users?status=active&role=admin&page=1
)。/orders?``total.gt``=100&``createdAt.lt``=2023-01-01
)。filter=status eq 'active' and role in ('admin')
)。A:
/items?orderId=123
(直接访问商品,通过参数关联订单)。/users/1/orders/123/items
(层级过深,依赖上下文)。Q:如何处理 API 的分页、排序和过滤?
A:
page
(页码)和size
(每页条数)参数,响应包含总条数和分页链接。sort
参数指定字段和方向(如sort=createdAt,desc
)。status=active
),复杂过滤用专用参数(filter=...
)。A:
Authorization
头传递 Token)。/admin/users
仅管理员可访问)。/users/1/orders
直观表示用户订单)。通过系统化掌握 RESTful API 的设计原则与实践技巧,既能应对 “如何设计开放平台 API” 等综合场景,也能精准回答 “PUT 与 PATCH 的区别” 等细节问题,展现高级程序员对 Web 服务架构的系统化理解与工程落地能力。