Restful 应用理解

Restful API 近年来应用愈来愈普遍,各大互联网公司纷纷推出了本身的 Restful API 服务。javascript

本文将从实际应用出发,从 REST 到 Restful 再到 Restful API ,逐一进行介绍和分析。html


REST 风格

REST 风格最先由 Roy Thomas Fielding 博士提出, REST 是一种系统架构设计风格,主要面向基于网络的软件架构设计。这一架构风格,包含了如下一些基本要求:java

客户-服务器

在 REST 风格中,最基本的要求就是对于一个程序来讲,应当分离用户接口和数据存储,改善用户接口跨平台迁移的可移植性,同时简化服务器组件,改善系统的可伸缩性。sql

对于这一点,目前咱们所接触到的大多数应用都已经使用了这一模式,不管是浏览器,仍是自主开发的客户端程序,其根本的实现方式都是采用了 客户-服务器 模式。客户端负责与用户之间的交互处理,而服务器端则实现数据存储以及相关的业务逻辑。json

同时,对于服务器端,完整的系统大部分状况下都会包含多个不一样的模块,这些模块之间的调用也应当遵循 客户-服务器 的模式,模块之间经过接口进行互相访问。segmentfault

无状态

服务端在设计接口时,应当设计为无状态接口。也就是说,服务器端不保存任何与客户端相关的状态上下文信息,客户端在每次调用服务端接口时,须要提供足够的信息,以供服务端完成操做。api

在无状态的设计中,服务端减小了保存客户端相关上下文数据,所以,一方面服务端可以更加容易的实现动态扩展,而不至于影响客户端使用;另外一方面则减小了服务端从故障中恢复的任务量。浏览器

但无状态也会带来额外的问题。客户端将须要保存完整的用户状态信息,在每次与服务端交互时可能须要增长与用户状态相关的上下文信息,这样将致使请求数据的重复和增大。缓存

缓存

根据接口的实际状况,应当在接口设计中增长缓存策略,服务端能够决定是否能够缓存当前返回的数据。经过此种方式,能够在必定程度上减小实际到达服务端请求,从而提升网络访问性能。安全

但缓存须要谨慎使用,缓存哪些数据,缓存过时时间都是须要根据实际状况进行设计。适当的缓存能够有效的提升系统效率,可是若是设计不当,将有可能致使大量的过时数据,进而影响系统运行。

通常而言,数据字典类数据、修改频率很是低的数据、实时性要求很低的数据等,这些数据能够设计必定的缓存策略,以提升系统运行效率。

系统分层

在设计系统,尤为是大型系统,一般须要将系统按照不一样的功能进行横向和纵向的分层。例如横向分层通常可分为交互层、服务层、数据层等,而纵向分层则一般会按照不一样的业务功能对系统进行切分。通过分层后,系统将划分为不一样的模块进行独立开发部署运行。系统分层后,不一样的模块能够独立进化,实现功能解耦,提升整个系统的可扩展性。

统一接口

统一接口,便是不一样系统模块之间的调用接口统一规范,使用统一的调用协议,统一的数据格式等。统一接口带来的是系统交互的规范化,接口调用与业务解耦,各模块独立进化。

以上便是对于 REST 风格的解释说明。REST 自己是一种系统架构设计风格,所以其更加偏向理论性。如下的内容将专一于实际场景中运用 REST 风格。


Restful 实现

REST 风格是面向网络的软件架构设计风格,其针对的是基于网络的软件架构。当软件架构设计符合 REST 风格时,则能够描述为该设计是 Restful 的。而在实际场景中,REST 论文中描述了应用 REST 风格基本方式,即 REST (表述性状态转移)。

面向资源

网络上的一个实体,一个具体信息,均可以描述为一个 资源 ,资源能够是文本、图片、音频、服务等具体存在。在网络中,每种资源都对应与一个 URI (统一资源标识符)地址,经过 URI 就能够访问到该资源。而咱们一般的上网,便是对资源的各类操做。

在 Restful 架构中,全部的接口应当采用面向资源的接口设计,即对于接口的访问地址指向其 URI 地址。

表述性

资源在网络上呈现出来的多是多种形式,例如 HTML 、 XML 、 JSON 、图片等等。而客户端与服务器之间则传输的是资源的这种具体表现形式。客户端与服务端的互动,本质上就是经过这些表现形式,实现对资源的操做。

按照面向资源接口设计的要求,一般所见到的 URI 地址中,*.html / *.xml / *.json 等扩展名,其实都指向了当前资源的具体表现形式,而 URI 严格意义上仅指向了资源实体,并不包含具体表现形式。

状态转移

为了使操做资源,也即便资源发生状态转移,按照 REST 的要求,客户端若想要操做服务端资源,须要经过 HTTP 协议进行操做。而在 HTTP 协议中,规定了若干用于具体操做的动词,指向了不一样的操做类型。

通常而言,对于资源的操做能够表示 CRUD 四类最基本的操做,即 增删改查 。而 HTTP 协议中的一般用如下动词表示这四类具体的操做:

  • GET :查询资源操做。

  • POST :新建资源操做,也能够用于更新资源。

  • PUT :更新资源操做。

  • DELETE :删除资源操做。

在实际应用中,客户端与服务端之间的交互,便是创建在 HTTP 协议之上,经过面向资源的接口地址,使用 HTTP 协议动词做为操做描述,进而实现客户端与服务端的交互过程。


Restful API 设计

在 REST 提出多年来,当前对于 REST 风格的应用最多的便是 Restful API 。

Restful API 通常分为对外和对内。对外的 Restful API 为面向公网的公共服务接口,此类接口通常能够经过公网直接访问,或是通过必定的安全认证后经过公网访问。而对内的 Restful API 则主要是一整套系统内部各个子系统或模块之间交互的标准接口,相对于对外的 Restful API 接口,内部 API 接口更加标准化。

按照 REST 的要求,Restful API 的设计能够总结出如下的一些具体要求。

HTTPS + 域名

Restful API 的无状态性,要求客户端须要在调用接口时传入足够的信息以供服务端用于操做指定的资源,这就有可能使得接口数据在网络传输过程当中遭到拦截致使更多的数据泄漏。所以在提供 Restful API ,特别是对外的 API 时,应当尽量的使用 HTTPS 协议,以确保传输过程的安全。

另外一方面,在 API 地址中使用域名,能够进一步解耦服务端与客户端,服务端能够更加容易的迁移和扩展,而不会影响服务端的使用。

例如:

https://open.domain.com/

实际应用过程当中,使用 HTTPS 协议,更多应用与对外的 Restful API 接口,而对内网的 Restful API 来讲,能够在信任内网安全的前提下,使用 HTTP 协议,以下降复杂度,提升效率。

URL 指向资源,HTTP 动词指向操做

按照 REST 的要求,Restful API 的 URL 地址应指向具体的一个资源,例如用户 user 。URL 中应当只包含资源名词,不该该包含指向操做的动词,例如新建、查询、修改、删除等。具体操做经过 HTTP 动词( GET / POST / PUT / DELETE )指定。

例如,传统的访问地址,获取用户信息:

https://open.domain.com/app/getUser

此时的 URL 地址指向了 获取用户 这一具体的操做过程,这也就是传统的 RPC 形式。而按照 Restful API 的设计,该实例将设计为以下形式:

https://open.domain.com/app/user

// HTTP GET 请求

此时的 URL 地址指向了 user 这一资源实体,而经过 HTTP 协议中的 GET 动词指定了该请求为 获取用户 请求。

指定 API 版本号

在设计 Restful API 时,特别是对外的 API ,一般须要考虑 API 多版本的问题,由于 API 会进行升级,而客户端则处于不可控状态,可能没法及时对 API 调用过程进行配合升级。所以,服务端须要提供对不一样版本 API 的支持,同时,客户端在调用 API 时也须要指定特定的版本号,以确保调用过程正常进行。

版本号的指定,能够在 URL 中,也能够在 HTTP 头信息中。

例如,在 URL 中指定版本号:

https://open.domain.com/v1/app/user

这种指定版本号的方式相对简单直观,但将致使指向统一资源的 URL 产生多个,增长了管理 URL 的成本和复杂度。

例如,在 HTTP 头信息中增长版本号:

https://open.domain.com/app/user

HTTP 头:
API-Vsersion: 1

以上实例中,在 HTTP 请求的头信息中增长了自定义字段,用于表示 Restful API 版本。这种方式不会产生多个 URL ,但其问题是不够直观和简洁,客户端和服务端增长了区分版本号的难度,在在一些特定状况下,例如浏览器端的 HTTP 请求,难以对 HTTP 请求的头信息进行更改。

指定参数

在 Restful API 请求中,可能须要根据不一样的状况进行过滤,须要增长操做参数。通常来讲,针对 GET 和 DELTE 请求须要增长操做参数的状况较多,而 POST 和 PUT 更多的是经过 HTTP 报文体提供操做数据信息。

指定参数能够经过两种方式:URL 地址参数,? 参数。

URL 地址参数:即在 URL 以后,继续按照 URL 格式拼接参数,服务端接到请求后,经过识别 URL 中字符串的位置,获取不一样的参数。

例如:

https://open.domain.com/app/user/123456/Adminhttps://open.domain.com/app/user/123456/Admin

在以上实例中, 123456 表明用户 ID 参数值, Admin 则表明用户类型参数值,后台解析该 URL 后便可根据字符串位置获取到特定的参数。

? 参数:即经过 QueryString 查询字符串的形式,拼接到 URL 以后,查询字符串的格式以下:

?key1=value1&key2=value2&...

例如:

https://open.domain.com/app/user?id=123456&type=Admin

以上实例中,服务端经过解析 ? 以后的字符串获取特定的参数。

使用 JSON 做为返回数据格式

相对于 XML 格式来讲,JSON 格式更加简洁易用,占用数据量更小,在以网络为基础,使用 HTTP 协议的 Restful API 中,使用 JSON 做为返回数据格式更加合理。

例如:

// JSON 格式
{"name":"user","type":"Admin"}

// XML 格式
<user><name>user</name><type>Admin</type></user>

使用安全认证机制

在使用 Restful API ,特别是对公网开放的 Restful API,一般须要经过必定的安全认证机制来进行实现访问控制。目前主流的方案是经过 OAuth2.0 实现安全认证。


Restful API 分析

Restful API 的兴起,证实了其具有相比于传统 RPC 接口的优点。当一样的,Restful API 在实际应用过程当中,也存在这本身的劣势和问题。

Restful API 优点

Restful API 充分利用了 HTTP 协议的设计,使用面向资源的接口设计,相对于传统 RPC 下降了接口设计的复杂度。

例如,使用传统 RPC 形式设计针对用户对象的 CRUD 操做:

// 新建用户
https://open.domain.com/app/addUser
// 查询用户
https://open.domain.com/app/retrieveUser
// 更新用户
https://open.domain.com/app/updateUser
// 删除用户
https://open.domain.com/app/deleteUser

在以上实例中,须要经过四个 URL 来实现 CRUD 操做。而经过 Restful API 设计,可为以下实例:

// GET: 查询用户;POST: 新建用户;PUT: 更新用户;DELETE: 删除用户 https://open.domain.com/app/user// GET: 查询用户;POST: 新建用户;PUT: 更新用户;DELETE: 删除用户 https://open.domain.com/app/user

在以上实例中,经过 HTTP 动词指定了不一样的 CRUD 操做,将接口 URL 简化为了同一个地址,仅须要改变 HTTP 动词便可实现不一样的操做。

另外一方面,相对于 SOAP/XML 形式的 RPC 服务,Restful API 采用 HTTP/JSON 的形式传递数据,下降了传输数据量,同时提升了数据解析的效率,单位时间内的负载能力会高于 SOAP WebService 服务。

例如,对于 SOAP WebService 来讲,基本的请求响应格式以下:

<soapenv:Envelopexmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header>
    </soapenv:Header>
    <soapenv:Body>
    </soapenv:Body>
</soapenv:Envelope>

而对于 Restful API 来讲,其请求格式符合 HTTP 协议的要求,返回格式则符合标准的 JSON 格式便可。

Restful API 劣势

Restful API 面向资源设计接口,而对于一些复杂操做来讲,接口设计难度将远大于 RPC 形式。

例如,用户登陆验证,使用 RPC 形式设计接口以下:

https://open.domain.com/app/checkUser

在以上实例中,对于 Restful API 而言,很难将该业务归类为 HTTP 动词中的某一种。又好比“下单”这一功能,它涉及到了订单、用户、支付帐户等多个资源实体的多种操做,所以一样也难以设计为 Restful API 。

Restful API 具有高效简洁的特色,但这也所以形成 Restful API 没有相似于 SOAP 协议的规范性协议,Restful API 中的数据格式、标准、安全性等都须要由开发者决定,这也就形成了没法创建统一的 Restful API 标准,做为客户端可能须要适配多种格式的 Restful API 。

Restful API 可能遇到的问题

当 Restful API 存在多版本时,服务端须要维护多版本的接口,这会致使更多的维护成本,并且随着 API 的不断升级,多版本的成本将会愈来愈高,如何通知客户端进行接口版本升级一样也是可能遇到的问题。

当使用 URL 地址参数形式时,对于可选参数,服务端难以实现正确的读取。在 API 存在可选参数的状况下,URL 地址中的参数位置是不固定的,所以服务端很难判断参数所处的正确位置。

针对特定的业务功能,难以彻底按照 Restful 要求进行设计。例如用户验证、订单提交等涉及到多个资源实体和多种操做的业务流程,其一个接口中须要完成多项相关联的操做,若使用 RPC 形式设计接口,则设计为一个统一的接口便可,而使用 Restful API 则可能出现多个接口且接口间存在调用依赖,这将会增长客户端和服务端的处理难度。

Restful 自己并无安全性方面的标准,须要根据不一样的使用场景设计 API 的安全控制方案。目前经常使用的安全方案便是经过 OAuth2.0 进行安全认证,但不一样的 API 在安全认证机制方面也会存在必定的差异,若是设计统一完善的安全机制,也是须要考虑的问题。


Restful API 使用场景

根据 Restful API 的特定,其应用场景能够参考如下的场景:

  • 资源集中型服务,例如针对用户的信息查询,针对订单的信息查询的等,这类型服务以资源实体为中心,操做大多为简单的 CRUD 操做,业务逻辑简单。

  • 访问量大,且对访问时效要求比较高的服务。Restful API 相对于 SOAP WebService 来讲,数据量更小,解析更快,在网络环境下可以提升访问的速度和承载能力。

  • 面向公网的,且安全性要求较低的开放型 API 服务。这类服务一般由开发者向公网的全部使用者开放,Restful API 的形式可以简化服务调用过程,提升访问效率。

对于复杂业务操做,例如保全申请提交,理赔申请提交等,使用 Restful API 形式难以进行设计,所以此类的业务可使用传统 RPC 的接口形式进行设计,SOAP WebService 或者 HTTP/JSON 形式的 RPC 都是可行的选择,使用 RPC 形式反而会更加简单。

选择哪一种方式的接口设计,须要根据实际的应用状况进行调整,没有最好的,只有最合适的。


传统 RPC 服务改造

在已经成型的系统当中,多数调用采用了 RPC 形式进行设计,并使用 SOAP WebService 做为具体的实现方式,并且开发者也已经习惯了使用了 RPC 的形式设计服务接口。在这种状况下,若想要向 Restful API 形式改造,将付出大量的改形成本。已有系统中存在错综复杂的调用逻辑,而接口也多数都是面向过程的,这种状况下改造接口,须要在接口设计上进行大幅改动才可以实现 Restful API。同时,开发者也须要在设计开发接口时转变思想,以面向资源的方式进行接口设计,这也是须要面临的问题。

而对于新建系统来讲,不存在历史接口,则能够从头按照 REST 风格进行设计,接口可设计为 Restful API,其成本要小于对已有系统的改造。


参考文章:

  1. 《架构风格与基于网络的软件架构设计》 Roy Thomas Fielding 博士论文

  2. 《理解RESTful架构》 http://www.ruanyifeng.com/blog/2011/09/restful.html

  3. 《RESTful API 设计指南》 http://www.ruanyifeng.com/blog/2014/05/restful_api.html

  4. 《SOAP Webservice和RESTful Webservice》 http://blog.sina.com.cn/s/blog_493a845501012566.html

 
文章转自《https://segmentfault.com/a/1190000006735330》,感谢做者分享!
相关文章
相关标签/搜索