【计算机通识】认识 RESTful API
RESTful API 不仅是一套规则,更是一种哲学和设计风格
1. 什么是 RESTful API?
首先,我们需要理解两个核心概念:
- REST: 表述性状态转移,由 Roy Fielding 博士在其博士论文中提出。它是一种软件架构风格,而不是标准。它是一组设计原则和约束条件,基于 HTTP 协议。
- RESTful API: 符合 REST 架构风格设计的 API。我们可以理解为 “REST 式的 API”。
简单来说,RESTful API 将网络上的所有事物(数据、服务)都抽象为资源。我们通过统一的接口(HTTP 方法)对资源进行操作,从而实现客户端与服务器的交互。
2. REST 的核心架构约束(六大原则)
要真正理解 RESTful,必须了解其背后的六个约束。满足这些约束的 API 才能称为 “RESTful”。
- 客户端-服务器: 关注点分离。客户端负责用户界面和用户体验,服务器负责数据存储、业务逻辑和安全。两者可以独立演化。
- 无状态: 这是最关键的原则之一。 每个来自客户端的请求必须包含服务器处理该请求所需的所有信息。服务器不应存储任何客户端上下文。会话状态完全由客户端负责(例如,通过 Token)。
- 好处: 可伸缩性高,服务器无需维护状态,可以轻松部署到集群。
- 坏处: 每次请求可能需要携带更多重复数据(如认证 Token)。
- 可缓存: 响应必须明确标示自己是否可缓存,以防止客户端获取过期或不恰当的数据。这可以大大提高性能。
- 统一接口: 这是 REST 系统设计的核心。它简化了架构,解耦了各个部分。具体包括:
- 资源的标识(URI)
- 通过表述对资源执行操作(JSON, XML)
- 自描述消息
- 超媒体作为应用状态引擎(HATEOAS)
- 分层系统: 系统可以由多个层次组成,每个层次只知道相邻的层次。这提高了系统的可扩展性和安全性。例如,你可以在客户端和服务器之间加入负载均衡器、网关、防火墙等,而客户端无需知道这些细节。
- 按需代码(可选): 服务器可以临时向客户端传输逻辑代码(如 JavaScript),供客户端执行。这是唯一一个可选的约束。
3. RESTful API 设计最佳实践(具体怎么做)
现在,我们抛开理论,看看在实际开发中如何设计一个优秀的 RESTful API。
3.1. 面向资源设计 URI
URI 的核心是标识资源,而不是动作。
-
使用名词,而非动词:
- 不推荐:
/getUsers,/createOrder,/deleteProduct/123 - 推荐:
GET /users,POST /orders,DELETE /products/123
- 不推荐:
-
资源使用复数名词:
GET /users(获取所有用户)GET /users/123(获取 ID 为 123 的用户)
-
使用嵌套结构表达关联关系:
GET /users/123/orders(获取用户 123 的所有订单)GET /users/123/orders/456(获取用户 123 的 ID 为 456 的订单)
-
使用连字符
-提高可读性,避免下划线_:GET /published-articles(而非/published_articles)
-
使用小写字母:
GET /users(而非/Users)
3.2. 正确使用 HTTP 方法(动词)
HTTP 方法定义了要对资源执行的操作,这是 “统一接口” 的关键。
| HTTP 方法 | 描述 | 对应 SQL | 幂等性 | 安全性 |
|---|---|---|---|---|
| GET | 获取资源(一个或多个) | SELECT | 是 | 是 |
| POST | 创建新资源 | INSERT | 否 | 否 |
| PUT | 完整更新资源(客户端提供完整资源) | UPDATE | 是 | 否 |
| PATCH | 部分更新资源(客户端提供要修改的字段) | UPDATE | 否 | 否 |
| DELETE | 删除资源 | DELETE | 是 | 否 |
重要概念解释:
- 幂等性: 无论执行多少次,效果都一样。
GET,PUT,DELETE是幂等的。例如,多次DELETE /users/123,结果都是用户 123 被删除。 - 安全性: 不改变服务器状态。只有
GET是安全的。
示例:
GET /users-> 200 OK (用户列表)POST /users(Body: 用户信息) -> 201 Created (创建成功)GET /users/123-> 200 OK (用户 123 的详情)PUT /users/123(Body: 完整的用户信息) -> 200 OK (更新成功)PATCH /users/123(Body:{"name": "新名字"}) -> 200 OK (部分更新成功)DELETE /users/123-> 204 No Content (删除成功,无返回体)
3.3. 合理利用 HTTP 状态码
状态码用于告知客户端请求的结果。不要在所有响应中都返回 200 OK,然后在 Body 里说明错误。
-
2xx 成功:
200 OK- 通用成功状态。201 Created- 资源创建成功。响应头Location应包含新资源的 URI。204 No Content- 请求成功,但无内容返回(如DELETE成功)。
-
4xx 客户端错误:
400 Bad Request- 通用客户端错误,服务器无法理解请求(如参数错误)。401 Unauthorized- 未认证,需要身份验证。403 Forbidden- 服务器理解请求,但拒绝授权(认证成功但权限不足)。404 Not Found- 资源不存在。405 Method Not Allowed- 不允许的 HTTP 方法。409 Conflict- 请求与当前服务器状态冲突(如修改旧版本数据)。
-
5xx 服务器错误:
500 Internal Server Error- 通用服务器错误。
3.4. 返回统一的 JSON 响应体
即使出错,也应返回结构化的 JSON 数据。
成功响应:
{"code": 200,"message": "success","data": {"id": 123,"name": "张三","email": "zhangsan@example.com"}// 可以加入分页信息等// "pagination": { ... }
}
错误响应:
{"code": 404,"message": "用户不存在","timestamp": "2023-10-25T10:30:00Z","path": "/api/v1/users/999","details": "更多错误细节..."
}
3.5. 提供 API 版本管理
API 会演化,必须进行版本控制,避免破坏现有客户端。
-
URI Path 方式(最常用):
GET /api/v1/usersGET /api/v2/users
-
Query Parameter 方式:
GET /api/users?version=1
-
HTTP Header 方式:
GET /api/usersHeaders: Accept: application/vnd.myapi.v1+json
推荐使用 URI Path 方式,因为它最直观、最简单。
3.6. 数据过滤、排序、搜索和分页
对于集合资源,这些功能是必不可少的。
- 过滤:
GET /users?role=admin&status=active - 搜索:
GET /users?name=张(模糊搜索名字中含 “张” 的用户) - 排序:
GET /users?sort=-created_at,username(-表示降序) - 分页:
GET /users?page=2&limit=20或GET /users?offset=20&limit=20
3.7. 安全性
- 始终使用 HTTPS。
- 身份认证: 使用标准方案,如 JWT (JSON Web Tokens)、OAuth 2.0。Token 通常通过
Authorization请求头传递:Authorization: Bearer <token>。 - 授权: 确保用户只能访问其权限范围内的资源。
- 限流: 防止 API 被滥用,应返回
429 Too Many Requests。
3.8. 超媒体 API (HATEOAS)
这是 REST 最高级的约束,但实践中并不总是被实现。它使 API 变得“可发现”。
在响应中提供相关资源的链接:
{"id": 123,"name": "张三","links": [{"rel": "self","href": "/api/v1/users/123","method": "GET"},{"rel": "orders","href": "/api/v1/users/123/orders","method": "GET"},{"rel": "update","href": "/api/v1/users/123","method": "PUT"}]
}
客户端可以通过解析这些 links 来导航整个应用,而无需硬编码 URI 结构。
总结:一个好的 RESTful API 是什么样的?
一个优秀的、符合规范的 RESTful API 应该具备以下特点:
- 直观的: URI 清晰明了,使用名词标识资源。
- 语义化的: 正确使用 HTTP 方法和状态码。
- 一致的: 响应格式、错误处理、命名规则在整个 API 中保持一致。
- 无状态的: 不依赖服务器端的会话。
- 健壮的: 能妥善处理各种异常和错误。
- 安全的: 使用 HTTPS、适当的认证和授权机制。
- 可维护和可扩展的: 通过版本控制来管理迭代。
