RESTful API
一、RESTful API概述
1.1 定义
REST(Representational State Transfer)即表现层状态转移,是一种针对网络应用的设计风格,主要用于设计分布式超媒体系统。RESTful API 则是遵循 REST 架构原则的应用程序接口,允许客户端和服务器通过 HTTP 协议进行交互。它采用资源定位的思维模式,将所有的操作都视为对资源的操作,以使系统更加简洁、易于理解和扩展。
1.2 核心概念
- 资源(Resource):RESTful API 中的每一个对象、实体或数据都被抽象为一个资源。例如,用户、文章等都可以作为资源。每个资源都通过一个唯一的 URI(统一资源标识符)标识。比如,
/users/123表示id为123的用户资源,/posts/456表示id为456的文章资源。 - URI(统一资源标识符):用于标识资源的地址,通常使用 URL(统一资源定位符)作为 URI。
- HTTP 动作(HTTP Methods):依赖于 HTTP 协议的常见方法来对资源进行操作,每个 HTTP 方法对应不同的操作:
- GET:获取服务器上的资源。
- POST:在服务器上创建新的资源。
- PUT:更新服务器上的资源。
- DELETE:删除服务器上的资源。
- 无状态(Statelessness):每个请求都应该是独立的,服务器不会在请求之间保存客户端的状态。每次请求都必须包含理解请求所必需的信息。
- 表现层状态转移(Representational State Transfer):资源的表现形式可以是 JSON、XML、HTML 等格式,通常 RESTful API 使用 JSON 作为数据交换格式,因为它轻量且易于解析。客户端通过接收资源的表现形式(如 JSON、XML)来感知资源的变化,从而实现状态的“转移”。
二、RESTful API的特点和优势
2.1 特点
- 资源导向:所有内容都被抽象为资源(如 User、Order、Article 等),每个资源都有一个唯一的标识符(URI)。例如,
/users表示用户资源,/users/1表示 ID 为 1 的用户。 - 使用标准协议:基于 HTTP 协议,直接使用其方法(GET、POST 等)来操作资源。
- 无状态通信:每次请求都包含所有上下文,不依赖服务器保存状态。这使得服务器可以更加容易地进行扩展和负载均衡,因为每个请求都是独立的,不需要考虑之前的请求状态。
- 统一接口:接口风格统一、易于理解和使用。通过标准的 HTTP 方法(GET、POST、PUT、DELETE 等)和资源标识符(URI)访问资源,简化了系统的整体架构,提升了互操作性。
- 可缓存:客户端可根据响应头对资源进行缓存,提高性能。利用 HTTP 协议的缓存机制,允许中间件或客户端缓存响应结果,减少不必要的网络请求,从而提升响应速度和减轻服务器负担。
- 分层架构:客户端无需知道请求最终由谁处理(例如中间层、负载均衡等)。允许通过中间层(如代理服务器、网关)来处理请求,每层只需与相邻层通信,增强了系统的安全性、可扩展性和灵活性。
- 按需代码(可选):客户端可以从服务器下载代码或脚本,以扩展其功能,增加了系统的灵活性和可扩展性。
2.2 优势
- 简洁易懂:使用 HTTP 协议的标准方法和 URI,可以让 API 的设计和使用变得简单。通过 URL 和 HTTP 动词的组合,可以明确地表示对特定资源的操作意图。
- 灵活性:资源可以有不同的表示形式(JSON、XML 等),同时 HTTP 方法明确区分不同的操作。客户端可以根据自身需求选择合适的数据格式。
- 扩展性强:通过一致的接口设计,可以很容易地扩展和维护 API。随着应用程序的发展,可以轻松地添加新的资源和操作,而不会影响现有的 API 结构。
- 无状态性:简化了服务器端的设计,增强了系统的可扩展性。服务器不需要保存客户端的状态信息,使得服务器可以更容易地进行扩展和负载均衡。
- 跨平台:基于 HTTP 协议,可以被任何支持 HTTP 的客户端调用,适用于各种应用场景,特别是需要跨平台和跨语言交互的系统。
三、RESTful API的设计原则
3.1 基于资源
将网络上的每个实体或概念视为唯一资源是一个关键原则。通过 URL 来表示这些资源,使得资源的定位更加清晰和直观。例如,一个博客文章可以被表示为 /articles/123,其中 “articles” 表示文章资源的集合,“123” 是具体某一篇文章的唯一标识符。这种方式使得开发者和用户都能够轻松地理解和访问特定的资源。以电商平台为例,商品可以表示为 /products,每个具体的商品可以通过 /products/{productId} 来访问,其中 {productId} 是商品的唯一标识。
3.2 统一接口
- 资源标识(Resource Identification):每个资源都应有唯一的 URL。例如,用户资源可以通过
/users/{id}进行标识,其中{id}是用户的具体标识。 - 资源操作(Resource Manipulation Through Representations):通过表示(representation)来操作资源,而不是直接操作资源本身。使用标准的 HTTP 方法(GET、POST、PUT、DELETE 等)来操作资源。
- 自描述消息(Self - descriptive Messages):响应消息应包含足够的信息以便客户端无需额外文档即可理解。每个请求和响应都包含足够的信息,使得客户端能够理解如何处理它们。
- 无状态(Stateless):服务器不保存客户端的上下文信息,每次请求都是独立的。每个请求都必须包含足够的信息,使服务器能够理解和处理该请求,而不依赖于之前的请求。
3.3 使用标准的 HTTP 方法
主要使用 HTTP 方法来定义对资源的操作,常见的 HTTP 方法及其作用如下:
| HTTP 方法 | 操作 | 幂等性 | 安全性 | 示例 |
|---|---|---|---|---|
| GET | 获取资源 | ✅ | ✅ | GET /users 查看所有用户信息;GET /users/id 查看该 id 的用户信息 |
| POST | 创建资源 | ❌ | ❌ | POST /users 创建用户,可在 DATA 处带需要的参数 |
| PUT | 更新或替换资源 | ✅ | ❌ | PUT /users/id?name='张三'&age=20 修改该 id 的用户信息(name 和 age) |
| PATCH | 部分更新资源 | ❌ | ❌ | 对资源进行部分属性的更新 |
| DELETE | 删除资源 | ✅ | ❌ | DELETE /users/id 删除该 id 的用户信息 |
| HEAD | 获取资源的元数据 | ✅ | ✅ | |
| OPTIONS | 获取信息,关于资源的哪些属性是客户端可以改变的 | ✅ | ✅ |
3.4 无状态通信
每个请求必须包含服务器处理该请求所需的所有信息,服务器不依赖之前的请求上下文。这使得服务器可以更加容易地进行扩展和负载均衡,因为每个请求都是独立的,不需要考虑之前的请求状态。例如,当客户端发送多个请求时,服务器不需要记住之前的请求内容,只需要根据当前请求的信息进行处理。
3.5 返回适当的状态码
API 应返回适当的 HTTP 状态码,准确反映请求结果。常用的状态码如下:
| 状态码 | 含义 | 说明 |
|---|---|---|
| 200 | OK | 服务器成功返回用户请求的数据,该操作是幂等的(Idempotent),通用成功。 |
| 201 | Created | 资源已创建,通常用于 POST 请求。 |
| 204 | No Content | 请求成功,但无返回内容,通常用于 DELETE 请求。 |
| 400 | Bad Request | 请求参数有误,服务器无法处理。 |
| 401 | Unauthorized | 认证失败,客户端需要提供身份验证。 |
| 403 | Forbidden | 没有权限访问资源,服务器理解请求,但拒绝执行,通常由于权限问题。 |
| 404 | Not Found | 请求的资源不存在。 |
| 500 | Internal Server Error | 服务器内部错误。 |
3.6 过滤信息
如果记录数量很多,服务器不可能都将它们返回给用户。API 应该提供参数,过滤返回结果。常见的参数如下:
?limit=10:指定返回记录的数量。?offset=10:指定返回记录的开始位置。?page=2&per_page=100:指定第几页,以及每页的记录数。?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。?animal_type_id=1:指定筛选条件。
3.7 支持 HATEOAS(超媒体作为应用程序状态引擎)
HATEOAS 要求客户端能够通过服务器返回的超链接(URL)导航到相关资源。简而言之,HATEOAS 要求 API 的响应不仅包含资源数据,还应该包含与资源相关的操作链接,帮助客户端更好地理解如何进行下一步操作。例如,获取用户信息时,除了返回用户的详细数据外,API 还可以提供相关操作的链接:
|
|
3.8 数据格式
返回数据格式通常使用 JSON 或 XML,其中 JSON 因其轻量级和易读性,已成为 RESTful API 事实上的数据交换格式。统一返回 JSON 格式,包含数据、状态码和错误信息,例如:
|
|
3.9 版本控制
当 API 发生变化时,可以通过版本号来管理不同版本的 API,以保持向后兼容性。常见的版本控制策略有:
- URL 路径版本:如
/v1/resource,优点是简单、显式、易缓存;缺点是不够优雅、URL 膨胀。 - 请求头版本:如
X - API - Version: 1,优点是 URL 干净、松耦合;缺点是难调试、可能被代理移除。 - 内容协商版本:如
Accept: application/vnd.example.v1+json,优点是 RESTful、标准 HTTP 头;缺点是复杂、客户端支持不一。 - 查询参数版本:如
/resource?version=1,优点是简单、显式;缺点是不是 RESTful、URL 污染。
四、RESTful API的设计示例
以一个简单的博客平台为例,设计其 RESTful API:
4.1 资源列表
- 用户(
/users) - 文章(
/articles) - 评论(
/comments)
4.2 操作设计
| 操作 | HTTP 方法 | URL | 说明 |
|---|---|---|---|
| 获取所有用户 | GET | /users |
返回所有用户的列表 |
| 获取特定用户 | GET | /users/{id} |
返回指定 ID 用户的详细信息 |
| 创建用户 | POST | /users |
根据请求体中的数据创建新用户 |
| 更新用户信息 | PUT | /users/{id} |
更新指定 ID 用户的信息 |
| 删除用户 | DELETE | /users/{id} |
删除指定 ID 的用户 |
| 获取所有文章 | GET | /articles |
返回所有文章的列表 |
| 获取特定文章 | GET | /articles/{id} |
返回指定 ID 文章的详细信息 |
| 创建文章 | POST | /articles |
根据请求体中的数据创建新文章 |
| 更新文章信息 | PUT | /articles/{id} |
更新指定 ID 文章的信息 |
| 删除文章 | DELETE | /articles/{id} |
删除指定 ID 的文章 |
| 获取特定文章的评论 | GET | /articles/{id}/comments |
返回指定 ID 文章的所有评论 |
| 创建评论 | POST | /articles/{id}/comments |
在指定 ID 文章下创建新评论 |
| 删除评论 | DELETE | /comments/{id} |
删除指定 ID 的评论 |
五、RESTful API的实现
5.1 服务端实现(以 Node.js 为例)
|
|
5.2 客户端调用(以 JavaScript Fetch 为例)
|
|
六、RESTful API的应用场景
6.1 Web 服务
提供 Web 服务,如社交媒体、电商网站等。前端(如 JavaScript、Angular、React 等)可以通过 RESTful API 与后端服务器进行通信,获取和更新数据。例如,一个电商网站的前端可以使用 RESTful API 从服务器获取商品列表、用户信息等,并将用户的订单信息发送到服务器进行处理。
6.2 移动应用
移动应用通过 RESTful API 与服务器交互,获取和更新数据,实现用户登录、数据同步等功能。Android 和 iOS 应用可以使用 RESTful API 与服务器交互,提供丰富的用户体验。
6.3 物联网(IoT)
设备通过 RESTful API 与服务器通信,实现数据采集和控制。物联网设备可以通过 RESTful API 将采集到的数据发送到服务器,同时接收服务器的控制指令。
6.4 微服务架构
微服务之间通过 RESTful API 进行通信和协作。每个微服务都可以暴露自己的 RESTful API,其他微服务可以通过调用这些 API 来获取所需的数据或执行特定的操作。例如,一个电商系统可能由用户服务、商品服务、订单服务等多个微服务组成,这些微服务之间可以通过 RESTful API 进行数据交互和业务协作。
6.5 企业级应用集成
企业内部的不同系统之间可以使用 RESTful API 进行集成。例如,企业的客户关系管理系统(CRM)和企业资源规划系统(ERP)可以通过 RESTful API 进行数据交换,实现信息共享和业务流程的协同。
七、RESTful API与传统 API的对比
| 比较项 | RESTful API | 传统 API 风格 |
|---|---|---|
| 接口风格 | 资源导向,结构清晰 | 动作导向,接口混乱 |
| 动作表示 | 使用 HTTP 方法表示动作 | 接口路径中包含动词(如 /getUser) |
| 可读性 | 高,可直观理解操作含义 | 低,需要阅读文档才能理解 |
| 维护性 | 易于扩展和维护 | 扩展性差,接口膨胀 |
| 数据传输格式 | 通常使用 JSON 或 XML,有明确标准 | 可能使用多种格式,无明确标准 |
| 状态与缓存 | 强调状态无关性,可利用 HTTP 缓存机制 | 可能依赖服务器端状态,缓存策略不一致 |
| 安全性和认证 | 支持各种安全性措施,如 HTTPS、认证、授权等 | 可能缺乏统一的安全标准 |
| 接口一致性 | 统一接口,易于使用 | 接口设计松散,不一致 |
| 资源关联性 | 在响应中提供相关资源的链接,具有自描述性 | 通常不提供自描述性 |
综上所述,RESTful API 以其简洁、灵活、可扩展等优点,成为现代 Web 开发中主流的 API 设计风格之一,广泛应用于各种网络应用场景中。在设计和开发 RESTful API 时,遵循其设计原则和最佳实践,能够构建出高效、易用、可维护的 API 系统。