RESTful 真正意味着什么?(What Does RESTful Really Mean? )

By | 2018年7月12日

Last month, I attended Fast Track to RESTful Microservices training at Skillsmatter.
During the course, we explored what REST APIs can offer to web
applications in general and microservices communication in particular.
Personally, the most important outcome of the course is a better
understanding of what REST really means and what are its pros and cons.

Image title

During
most of my career, I’ve been focused on mobile technologies, and
therefore on the consuming side of web APIs. Most APIs that I’ve ever
consumed were supposed to be RESTful, but now that I better understand
what RESTful means I can say that 99% of them weren’t even close to
RESTful (clients are broken because of something being added in the
server side sound familiar?).

上个月,我在Skillsmatter参加了一个关于RESTful微服务快速进阶的培训课程。课程着重探讨了REST API在web应用和微服务交互方面起到的作用。对我来说,这个课程给我最大的收获是让我更好地理解REST,以及它的优点和不足。

过去我大部分工作是在移动技术领域,也就是web API的调用端。我过去所调用的大部分API被认为是RESTful的,不过现在我对RESTful有了更深的理解,我敢说那些API里有99%都算不上RESTful。

Definition

The term REST stands for “REpresentational State Transfer.” A possible formal definition of it could be as follows.

Architectural
API style based on transferring a representation of state (documents)
between client and server in order to progress the state of an
application.

Constraints

To consider
applications as RESTful, applications need to conform to the following
REST constraints. Complying with the constraints enables a distributed
hypermedia system to have the following desirable non-functional
properties: performance, scalability, simplicity, extensibility,
visibility, portability, and reliability.

Client-server

A client-server model favors separation of concerns so that clients are not concerned with data storage. Thus, clients code portability is improved. On the other hand, the server is not concerned about user interface or user state, so that server can be simpler and more scalable. Servers and clients can be developed independently, as long as they conform to the defined contract.

定义

REST是“呈现状态转移(REpresentational State Transfer)”的缩写。或许可以这样来定义它:一种API的架构风格,在客户端和服务端之间通过呈现状态的转移来驱动应用状态的演进。

约束

要让应用RESTful化,需要遵循以下约束。遵循了这些约束的分布式系统,就会拥有如下非功能属性:性能,伸缩性,易用性,扩展性,可见性,可移植性和可靠性。

CS模式

CS模式通过分离客户端和服务器端的关注点,让客户端不再关注数据的存储问题,从而提高客户端代码的可移植性。另一方面,服务器端不再关注用户界面和用户状态,从而变得更简单,提高了伸缩性。服务器端跟客户端可以独立开发,只要它们都遵守契约。

Stateless

Client
context is never stored on the server between requests. Each request
has to contain all the necessary information. A stateless server
improves scalability by allowing the server to quickly free resources and simplifies implementation. Reliability eases recovering from partial failures. Visibility, monitoring system does not have to look beyond a single request to determine the nature of the request.

One
of the drawbacks of having a stateless server is decreased network
performance, as all the needed data has to be sent in each request.

Cacheable

REST
applications are web systems; therefore, clients and intermediaries can
cache responses. Responses themselves must be defined as cacheable, or
not, to prevent clients from reusing stale data that could reduce reliability.
If stale data in the cache differs significantly from the data that
would have been generated the request been handled by the server.
Caching could eliminate some client-server interaction, thus improving scalability, efficiency, and user-perceived performance by reducing average latency.

无状态

客户端上下文在多个请求之间是绝不会保存在服务器上的。每个请求必须包含必要的信息。无状态的服务器通过快速释放资源和简化实现提高了可伸缩性。可靠性使得从局部失败中恢复变得容易。很明显,监控系统不必通过考虑单个请求来判断请求的性质。

无状态服务器的一个缺点是降低了网络性能,因为所有需要的数据必须在每次请求中发送。


可缓存

REST应用程序是web系统,因此客户端和中间层可以缓存响应。响应必须被定义为可缓存或不可缓存的,以防客户端重复使用旧数据导致降低可靠性。如果缓存中的陈旧数据与已生成的请求的数据显著不同,则由服务器处理请求。缓存可以消除一些客户端和服务器之间的交互,这就提升了可伸缩性、效率和通过减少平均延迟达到的用户可感知的性能。 

Uniform interface

Using
a uniform interface simplifies and decouples the architecture and
favors the independent evolution of different parts. As explained later
on in this post, URIs, resources and hypermedia help to produce a
standard interface that improves the visibility of interactions, simplifies the overall system architecture and encourage independent evolution. The trade-off is that it degrades efficiency since information is transferred in a standard format rather one which is particular to an application’s needs.

Layered system

Using
a layered system reduces complexity by constraining component behavior
such that each element cannot access beyond its immediate layer. Favors
substrate independence by restricting knowledge of other parts of the
system. Layers can encapsulate legacy components and protect new
services from legacy clients. Intermediaries can be used to improved scalability
by enabling load balancing across networks. The main trade-off is that
layered systems add overhead and latency to the data processing,
therefore, reducing user-perceived performance.

Code-On-Demand (Optional)

REST allows clients to extend their functionality by downloading and executing code scripts. This simplifies clients and improves extensibility. On the other hand, it reduces visibility, which is why it is only an optional constraint.

统一的接口

使用统一的接口降低了系统复杂度和耦合度,让系统的不同部分可以独立演化。稍后会解释URI,资源和超媒体是如何通过生成标准接口来提升用户交互可见性,降低系统复杂度,促进系统组件独立演化的。但是我们需要在效率方面做出妥协,毕竟消息是通过标准格式传输的,并不能满足所有应用对消息格式的要求。

分层的系统

分层系统通过约束组件的行为来降低系统复杂度,组件不能越过它们的媒介层去访问其它层。通过组件的阻断来保持层间的独立性。遗留的组件可以被封装成新的层,不让旧的客户端访问。媒介层可以通过负载均衡来提升伸缩性。分层系统存在的主要不足,是它给数据处理增加了一些额外的开销,增加了延迟,对用户体验有所影响。

按需编码

REST允许客户端通过下载执行脚本来扩展它们的功能,简化了客户端,也提升了扩展性。但这同时也降低了可见性,所以这个约束不是必须遵循的。

Elements

REST has several elements in its toolbox to build stateless, scalable and simple web APIs.

  • HTTP

  • Resources

  • URIs

  • Hypermedia

HTTP – Document Transfer Application Protocol

REST
is usually used along with HTTP as its transfer protocol as it offers
several advantages. Among them are HTTP verbs, status codes, and
headers.

Verbs

Instead of defining new verbs for
every possible behavior in our web service, HTTP introduces a standard
set of verbs to handle similar situations in the same way, removing
unnecessary variation and creating a more intuitive API. Each verb has a
different combination of two properties that make them suitable for
different scenarios.

  • Idempotent: The operation can be repeated in the event of failures.

  • Safe: The operation has no side-effects for which the client is responsible.

元素

REST提供了以下几种元素来构建无状态,可伸缩的web API。

  • HTTP协议

  • 资源

  • URI

  • 超媒体

HTTP – 文本传输协议

REST一般使用HTTP作为它的传输协议,因为HTTP提供了一些很好用的特性,如HTTP动词,状态码和头部信息。

HTTP动词

HTTP并没有定义很多动词来描述web服务中可能出现的行为,它只用了一个标准动词集合来处理各种相似情况,从而让API变得更直观。每个动词通过两种属性的组合来满足不同的场景需求。

  • 幂等性:操作可以被重复执行,就算在失败以后。

  • 安全性:对客户端来说操作不会产生副作用。

GET

Used to read state from the server. Being a safe
operation, it can be executed multiple times without risk of data
modification or corruption – calling it once has the same effect as
calling it ten times. As an idempotent operation, making multiple identical requests has the same result as a single request.

POST

Usually used to create some state on the server. It’s neither safe nor idempotent.
Therefore multiple requests will create several resources on the
server. As a non-idempotent operation, POST should not be used for
operations that deal with money, as in the case of a failed request is
done multiple times, we would potentially be transferring money or
paying multiple times.

PUT

It’s mostly used to update state on the server, although it can also be used to create state. It’s Idempotent but not safe
as it changes the state of the server. Being an idempotent made PUT a
good candidate, for instance, for operations related to money.

DELETE

It’s used to delete state on the server. It’s idempotent but not safe, as it removes state from the server. It’s idempotent as deleting state that has previously been deleted should not have further implications.

GET

用来从服务器端读取状态。这个操作是安全的,所以它可以被执行很多次而不会对数据有任何影响,也就是说执行它一次跟执行十次是一样的效果。从幂等性方面来看,多次请求跟单个请求总能得到相同的结果。

POST

一般用来在服务器端创建某种状态。这个操作不具备幂等性跟安全性,所以多次请求会在服务器端创建多个资源。因为POST是不幂等的, 所以不应该被用来做跟金钱有关系的操作,试想一次失败的请求如果被执行多次,那么很可能转账或者支付也被执行了多次。

PUT

虽然它也可以被用来创建状态,但主要还是用来在服务器端更新状态的。它是幂等的,但不安全,因为它会改变服务端的状态。因为它的幂等性,PUT可以被用来处理跟金钱有关系的操作。

DELETE

用来在服务器端删除状态。它也是幂等非安全的,因为它会移除服务端的状态。它之所以是幂等的,是因为重复删除一个状态的结果是一样。

Response Status Codes

The HTTP status codes
provide metadata in the response to the state of the requested
resources. They are part of what makes The Web a platform for building
distributed systems. They are divided into the following categories:

  • 1xx — Metadata.

  • 2xx — Everything is fine.

  • 3xx — Redirection.

  • 4xx — Client did something wrong.

  • 5xx — Server did something wrong.

Headers

The HTTP headers
are components to pass additional information in requests and
responses. Headers consist of a case-insensitive name followed by a
colon and its value. Headers could be grouped as:

  • General headers: Apply to both requests and responses but there is no relation to the data transmitted in the body.

  • Request headers: Contain more information about the resource being fetched or about the client making the request.

  • Response headers: Contain additional information about the response.

  • Entity headers: Add information about the body of the entity, like content-length or MIME-type.

响应状态码

HTTP在请求资源的响应里提供了元数据信息,也就是状态码。它们是web平台之所以能用来构建分布式系统的重要因素。它们被分为以下几类:

  • 1xx —— 元数据

  • 2xx —— 正确的响应

  • 3xx —— 重定向

  • 4xx —— 客户端错误

  • 5xx —— 服务端错误

头部信息

HTTP在消息头部里为请求响应提供了额外信息。每个头部由大小写敏感的关键字和值组成,中间用冒号隔开。头部信息被分为以下几类:

  • 一般头部:在请求跟响应里都有,跟消息体里传输的数据没有关系。

  • 请求头部:更多的是关于被请求资源或者客户端的信息。

  • 响应头部:响应的额外信息。


  • 实体头部
    :消息体的额外信息,比如content-length或MIMI-type。

Resources

A
resource is anything exposed by the system that has an identity.
Resources offer a way to adapt the application domain to web clients. An
image, a spreadsheet, a service or a collection of other resources are
some resource examples. The resources are fetched or send using a
certain representation (XML, JSON, etc.).

We deal with
resources representations, not with the resources themselves, following
the idea of “Pass-by-value.” Following the previous REST definition,
resources represent the documents being transferred across the network
to get work done. Resource state is a server-side concern, as it
represents the domain state, clients only fetch or send resource
representations to progress the application state. On the other hand,
application state is a client-side concern as it represents the progress
towards a particular application goal.

Resources should
be named as nouns as they represent concepts in the domain of a
particular system and are identified using URIs.

资源

资源可以是由系统暴露出来的任何具有唯一标识的东西。资源在应用领域跟客户端之间建立起了联系。一张图片,一个表格,或者它们的集合,都被看作资源。资源通过某种呈现方式被获取或被创建(XML,JSON等)。

我们与之打交道的是资源的呈现形式,并不是资源本身,这个跟值传递有点像。根据之前对REST的定义,资源代表了在网络上传输的文档。服务器端关心资源的状态,因为它们代表了领域的状态。而客户端只是获取或者发送资源的呈现状态,从而让应用的状态发生变化。客户端关心的是应用的状态,因为这些状态的变化跟应用所要达成的目标有关。

资源的名字都应该是具有名词性质的,它们代表的是系统中领域的概念,并用URI标识。

URIs (Uniform Resource Identifiers)

URIs
differentiate one resource from another. To access and manipulate a
resource, it needs to have at least one address. They are composed of a protocol + host + path.

Clients
should not be coupled to particular resources URIs as they can be
changed at server’s discretion. This is where hypermedia has the
greatest advantages, as it offers a way to decouple clients from
specific URIs and add semantics to the application protocol.

Hypermedia

Hypermedia
informs the client about what it can do next, through the use of
hypermedia controls (links and forms) in the responses, and the
particular URI to do it. The concrete hypermedia format for a particular
application is defined in the application Media Type.

Hypermedia links are composed by a href attribute that specifies the URI to access the linked resource and a rel
attribute that defines the meaning of the relationship, therefore,
adding semantics to the state transitions in the application. The use of
links allows the server to advertise new capabilities by including new
links in the responses without breaking existing clients. As long as the
server maintain previously defined links in the responses, clients
would be able to follow them just as they were before the new state was
added. Clients would need to be updated only if they need to access the
new state. Another hypermedia advantage is that it introduces
discoverability by providing a way of making a discoverable and
self-documenting protocol.

URIs (Uniform Resource Identifiers)

URIs用来唯一标识资源。要访问或者操作一个资源,最起码要知道资源的地址。它们由协议+服务器地址+路径组成。

客户端不应该与资源的URI有太多耦合,因为服务端可能随意改变它们的值。在这一点上,超媒体更具优势。它提供了一种解耦客户端跟URI的方式,并在应用协议中加入新的语义。

超媒体

超媒体通过超媒体控件(比如链接跟表单)或者URI告诉客户端接下来可以做什么。针对特定应用的超媒体格式是在应用的Media Type里定义的。

超链接由href属性和rel属性组成,href指定要访问资源的URI,rel定义了资源跟URI的关系。超媒体通过它们向应用的状态转移增加新的语义。服务端通过在响应中增加新的超链接来扩展新的功能,而不会对客户端造成影响。只要服务端在响应里一直保留之前的链接,客户端可以像之前那样工作,只是在要访问新资源的时候才需要更新。超媒体的另一个优势是它引入了可发现性,它提供了一种可以暴露资源的方式,而且它是一种自文档的协议。

Clients start interacting with
the app through a fixed URL, and from thereon all further actions
happen by the client following the links, formatted using the media
type, and provided by the server in each response.

Media
types and links define the contract between the application server and
the client. The client interacts with the system by navigating the
application state using the links. This is what HATEOAS (Hypermedia as the engine of application state) really means.

Hypermedia (in addition to the already defined elements) is what RESTful really means.

Richardson Maturity Model

This
model has helped me a lot to understand what REST means and how to
explain the properties of a web application. It divides the components
of a REST system into three levels and provides a way to understand the
ideas, concepts and the advantages of RESTful thinking. I’d say that
it’s an educational model rather than an assessment mechanism.

A detailed explanation of what Richardson Maturity Model is can be found at Martin Fowler’s blog.

客户端通过一个固定的URL跟app开始了交互,服务端在每一个响应里提供了后续操作的超链接,这些链接具有良好的媒体格式,客户端沿着这些链接可以做相应的操作。

超媒体跟链接定义了服务器跟客户端之间的契约。客户端通过链接与系统进行交互,这就是HATEOAS(超媒体作为应用状态的引擎)所表达的意思。

Richardson成熟度模型

这个模型帮助我更好地理解REST,以及如何去解释web应用的属性。它把REST系统的组件分为三个等级,并提供了一种方式去理解RESTful相关的想法,概念和优势。它更像是一种理论教育模型,而不是一种评审机制。

关于Richardson成熟度模型更具体的解释可以看这里


via:oschina

发表评论

电子邮件地址不会被公开。 必填项已用*标注