Skip to content

六个约束条件

IMPORTANT

原文:Learn REST API Design

REST 架构风格描述了六个约束条件。这些约束条件最早由 Roy Fielding 在他的博士论文中提出(请参见 https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm),并定义了 RESTful 风格的基础。

这六个约束条件如下:

统一接口(Uniform Interface)

统一接口约束定义了客户端和服务器之间的接口。它简化并解耦了架构,使得每个部分可以独立演化。统一接口的四个指导原则是:

基于资源(Resource-Based)

单个资源通过 URI 作为资源标识符在请求中被标识。资源本身与返回给客户端的表现形式是概念上分离的。例如,服务器并不会直接发送其数据库,而是发送一些 HTML、XML 或 JSON,这些内容表示一些数据库记录,这些记录可能以芬兰语表达并以 UTF-8 编码,具体取决于请求的细节和服务器的实现。

通过表现形式操作资源(Manipulation of Resources Through Representations)

资源的状态和表现形式(如 JSON、XML 或 HTML)是通过请求和响应进行交换的。在 REST 中,客户端通过操作资源的表现形式来与资源进行交互。例如,客户端可能会从服务器获取某个资源的表现形式,修改其内容后再将修改后的表现形式发送回服务器,从而实现对资源的操作。操作通常是通过 HTTP 方法(如 GET、POST、PUT、DELETE 等)来完成的。

自描述消息(Self-descriptive Messages)

每条消息包含足够的信息,以描述如何处理该消息。例如,可以通过互联网媒体类型(之前称为 MIME 类型)来指定应调用哪个解析器。响应还会明确指出其是否可以被缓存。

超媒体作为应用状态引擎(HATEOAS)

客户端通过请求体内容、查询字符串参数、请求头和请求的 URI(资源名称)来传递状态。服务端通过响应体内容、响应码和响应头来将状态传递给客户端。这在技术上被称为超媒体(或超文本中的超链接)。

除了上面描述的内容,HATEOAS 还意味着,在必要时,返回的主体(或头部)中包含链接,用于提供检索对象本身或相关对象的 URI。

任何 REST 服务必须提供的统一接口是其设计的基础。

无状态(Stateless)

由于REST是“表现层状态转移”的缩写,因此无状态性是其关键。实际上,这意味着处理请求所需的状态包含在请求本身中,无论是作为URI的一部分、查询字符串参数、请求体还是请求头。URI唯一标识资源,请求体包含该资源的状态(或状态变更)。然后,在服务器处理完毕后,相关的状态或重要的状态部分通过头信息、状态码和响应体传回给客户端。

我们大多数在行业中工作一段时间的人已经习惯于在容器中编程,容器提供了“会话”概念,可以在多个HTTP请求之间保持状态。在REST中,客户端必须包含所有信息,以便服务器能够完成请求,如果状态必须跨多个请求,客户端需要在必要时重新发送该状态。无状态性使得系统更具可扩展性,因为服务器无需维护、更新或传递会话状态。此外,负载均衡器也不必担心无状态系统的会话亲和性问题。

那么,状态和资源有什么区别呢?状态,或称为应用程序状态,是服务器为完成请求而关心的数据——当前会话或请求所需的数据。资源,或资源状态,是定义资源表示的数据——例如存储在数据库中的数据。可以将应用程序状态视为可能因客户端而异,并且每个请求可能不同的数据;而资源状态则在每个请求该资源的客户端之间保持一致。

有没有遇到过在 web 应用中使用后退按钮时出现问题,导致应用在某些点失灵,因为它期望你按特定顺序操作?那是因为它违反了无状态原则。有些情况并不遵循无状态原则,例如三方 OAuth、API 调用速率限制等。然而,应尽力确保应用状态不会跨越多个请求。

可缓存(Cacheable)

正如在全球信息网(World Wide Web)中,客户端可以缓存响应一样,响应必须隐式或显式地定义自己是否可缓存,以防止客户端在后续请求中重用过时或不合适的数据。良好管理的缓存机制可以部分或完全消除一些客户端与服务器之间的交互,进一步提高系统的可扩展性和性能。

客户端-服务器(Client-Server)

统一接口(Uniform Interface)将客户端和服务器分离。这种关注点分离的设计意味着,例如,客户端不需要关心数据存储,数据存储是服务器内部的,因此可以提高客户端代码的可移植性。服务器也不需要关注用户界面或用户状态,从而使得服务器可以更加简单和可扩展。只要接口不发生变化,服务器和客户端也可以独立替换和开发。

分层系统(Layered System)

客户端通常无法判断它是直接连接到最终服务器,还是通过中间层服务器进行连接。中间层服务器可以通过启用负载均衡和提供共享缓存来提高系统的可扩展性。层次化的设计也可以执行安全策略。

按需代码(Code on Demand)(可选)

服务器可以通过将逻辑传输到客户端来暂时扩展或定制客户端的功能,客户端能够执行这些逻辑。例如,这可能包括编译后的组件,如Java小程序,或客户端脚本,如JavaScript。

遵守这些约束,从而符合REST架构风格,将使任何类型的分布式超媒体系统具备一些理想的 emergent(渐现)特性,如性能、可扩展性、简洁性、可修改性、可见性、可移植性和可靠性。

CAUTION

RESTful与否?

REST架构中唯一可选的约束是“按需代码”(Code on Demand)。如果一个服务违反了其他任何约束,就不能严格称之为RESTful服务。