REST设计规范

一、REST的成熟模型   

当谈及REST成熟度时,一些人常常会引用Richardson所提出来的REST成熟度模型(Maturity Model),并视之为正确的度量方法。

                   



第一层次
     把HTTP这个应用层协议降级为传输层协议用,其实只是远程方法调用(RPC)的一种形式。SOAP 和 XML-RPC 都属于此类。

第二层次
      在架构中引入资源(Resource)的概念然而不同的URI只是作为不同的调用入口。
       最常见的错误就是在URI中包含动词,比如URI http://example.com/getOrder?orderId=1234,其实「资源」表示一种实体,所以应该是名词,动词应该放在HTTP协议中。而与此同时URI也有可能破坏HTTP GET的安全性和幕等性,比如某个客户端在http://example.com/updateOrder?id=1234&coffee=latte上执行GET(而不是POST),就能创建一笔新的咖啡订单(一个资源),按理来说GET请求不能改变服务的任何状态。

第三层次:每一个URI代表一种资源,支持HTTP动词。
      此时使用多个URI的话,需要让不同的URI代表不同的资源,同时使用多个HTTP方法操作这些资源,例如使用POST/GET/PUT/DELET分别进行CRUD操作。这时候HTTP头和有效载荷都包含业务逻辑,例如HTTP方法对应CRUD操作,HTTP状态码对应操作结果的状态。我们现在看到的大多数所谓RESTful API做到的也就是这个级别。

第四层次:HATEOAS,使用超媒体(hypermedia)作为应用状态引擎。
      在资源的表达中包含了链接信息。客户端可以根据链接来发现可以执行的动作。

从上述 REST 成熟度模型中可以看到,使用 HATEOAS 的 REST 服务是成熟度最高的,也是推荐的做法。对于不使用 HATEOAS 的 REST 服务,客户端和服务器的实现之间是紧密耦合的。客户端需要根据服务器提供的相关文档来了解所暴露的资源和对应的操作。当服务器发生了变化时,如修改了资源的 URI,客户端也需要进行相应的修改。而使用 HATEOAS 的 REST 服务中,客户端可以通过服务器提供的资源的表达来智能地发现可以执行的操作。当服务器发生了变化时,客户端并不需要做出修改,因为资源的 URI 和其他信息都是动态发现的。


二、REST VS SOAP

成熟度
SOAP虽然发展到现在已经脱离了初衷,但是对于异构环境服务发布和调用,以及厂商的支持都已经达到了较为成熟的情况。不同平台,开发语言之间通过SOAP来交互的web service都能够较好的互通
REST国外很多大网站都发布了自己的开发API,很多都提供了SOAP和REST两种Web Service,根据调查部分网站的REST风格的使用情况要高于SOAP。但是由于REST只是一种基于Http协议实现资源操作的思想,因此各个网站的REST实现都自有一套,在后面会讲诉各个大网站的REST API的风格。也正是因为这种各自实现的情况,在性能和可用性上会大大高于SOAP发布的web service,但统一通用方面远远不及SOAP。由于这些大网站的SP往往专注于此网站的API开发,因此通用性要求不高。 
总的来说SOAP在成熟度上优于REST。 

效率和易用性
       SOAP协议对于消息体和消息头都有定义,同时消息头的可扩展性为各种互联网的标准提供了扩展的基础,WS-*系列就是较为成功的规范。但是也由于SOAP由于各种需求不断扩充其本身协议的内容,导致在SOAP处理方面的性能有所下降。同时在易用性方面以及学习成本上也有所增加。 
       REST被人们的重视,其实很大一方面也是因为其高效以及简洁易用的特性。这种高效一方面源于其面向资源接口设计以及操作抽象简化了开发者的不良设计,同时也最大限度的利用了Http最初的应用协议设计理念。同时,在我看来REST还有一个很吸引开发者的就是能够很好的融合当前Web2.0的很多前端技术来提高开发效率。例如很多大型网站开放的REST风格的API都会有多种返回形式,除了传统的xml作为数据承载,还有(JSON,RSS,ATOM)等形式,这对很多网站前端开发人员来说就能够很好的mashup各种资源信息。 
       因此在效率和易用性上来说,REST更胜一筹。 

安全性
       这点其实可以放入到成熟度中,不过在当前的互联网应用和平台开发设计过程中,安全已经被提到了很高的高度,特别是作为外部接口给第三方调用,安全性可能会高过业务逻辑本身。 
       SOAP在安全方面是通过使用XML-Security和XML-Signature两个规范组成了WS-Security来实现安全控制的,当前已经得到了各个厂商的支持,.net ,php ,java 都已经对其有了很好的支持(虽然在一些细节上还是有不兼容的问题,但是互通基本上是可以的)。 
       REST没有任何规范对于安全方面作说明,同时现在开放REST风格API的网站主要分成两种,一种是自定义了安全信息封装在消息中(其实这和SOAP没有什么区别),另外一种就是靠硬件SSL来保障,但是这只能够保证点到点的安全,如果是需要多点传输的话SSL就无能为力了。安全这块其实也是一个很大的问题,今年在BEA峰会上看到有演示采用SAML2实现的网站间SSO,其实是直接采用了XML-Security和XML-Signature,效率看起来也不是很高。未来REST规范化和通用化过程中的安全是否也会采用这两种规范,是未知的,但是加入的越多,REST失去它高效性的优势越多。 

应用设计与改造: 
       我们的系统要么就是已经有了那些需要被发布出去的服务,要么就是刚刚设计好的服务,但是开发人员的传统设计思想让REST的形式被接受还需要一点时间。同时在资源型数据服务接口设计上来说按照REST的思想来设计相对来说要容易一些,而对于一些复杂的服务接口来说,可能强要去按照REST的风格来设计会有些牵强。这一点其实可以看看各大网站的接口就可以知道,很多网站还要传入function的名称作为参数,这就明显已经违背了REST本身的设计思路。 
       而SOAP本身就是面向RPC来设计的,开发人员十分容易接受,所以不存在什么适应的过程。 

总的来说,其实还是一个老观念,适合的才是最好的 
       技术没有好坏,只有是不是合适,一种好的技术和思想被误用了,那么就会得到反效果。REST和SOAP各自都有自己的优点,同时如果在一些场景下如果去改造REST,其实就会走向SOAP(例如安全)。 
       REST对于资源型服务接口来说很合适,同时特别适合对于效率要求很高,但是对于安全要求不高的场景。而SOAP的成熟性可以给需要提供给多开发语言的,对于安全性要求较高的接口设计带来便利。所以我觉得纯粹说什么设计模式将会占据主导地位没有什么意义,关键还是看应用场景。 
       同时很重要一点就是不要扭曲了REST现在很多网站都跟风去开发REST风格的接口,其实都是在学其形,不知其心,最后弄得不伦不类,性能上不去,安全又保证不了,徒有一个看似象摸象样的皮囊。 

REST设计的几种形式 
参看了几个大型网站的REST风格的API设计,这里做一下大致的说明: 

FaceBook: 

请求消息: 
       在URI设计上采取了类似于REST的风格。例如对于friends的获取,就定义为friends.get,前面部分作为资源定义,后面是具体的操作,其他的API也是类似,资源+操作,因此就算使用http的get方法都可能作了update的操作,其实已经违背了REST的思想,但是说到,其实那么复杂的业务接口设计下,要通过RUCD来抽象所有的接口基本是不实际的。在URI定义好以后,还有详细的参数定义,包括类型以及是否必选。 

响应消息: 
       有多种方式,XML,JSON。XML有XSD作为参考。有点类似于没有Head的SOAP,只不过这里将原来可以定义在WSDL中的XSD抽取出来了。 

Flickr: 
       请求消息: http://api.flickr.com/services/rest/?method=flickr.test.echo&name=value 
       这里就可以很明显看出它所定制的REST请求其实和RPC没有什么太大的区别。 
       
消息返回: 
正确处理返回 
<?xml version="1.0" encoding="utf-8" ?> 
<rsp stat="ok"> 
         [xml-payload-here] 
</rsp> 
错误处理返回 
<?xml version="1.0" encoding="utf-8" ?> 
<rsp stat="fail"> 
         <err code="[error-code]" msg="[error-message]" /> 
</rsp> 
 根据返回可以看出已经违背了REST的思想,还是把Http协议作为传输承载协议,并没有真正意义上使用Http协议作为资源访问和操作协议。 
 总的来说,只是形式上去模仿REST,自己搞了一套私有协议。 

Ebay: 
       请求消息: 采用xml作为承载,类似于SOAP,不过去除SOAP消息的封装和包头,同时在请求中附加了认证和警告级别等附加信息。 
       消息返回: 
       类似于SOAP消息,不过删除了SOAP的封装和包头,同时在返回结构中增加了消息处理结果以及版本等附加信息。 
       这个很类似于当前Axis2框架的做法,将SOAP精简,同时根据自身需求丰富了安全,事务等协议内容。 

Yahoo Maps: 
       请求消息: 采用REST推荐的方式,URI+Parameters。 
       返回消息: 
<?xml version="1.0" encoding="UTF-8"?> 
<ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="urn:yahoo:maps" 
xsi:schemaLocation="urn:yahoo:maps http://local.yahooapis.com/MapsService/V1/GeocodeResponse.xsd"> 
<Result precision="address"> 
    <Latitude>37.416384</Latitude> 
    <Longitude>-122.024853</Longitude> 
    <Address>701 FIRST AVE</Address> 
    <City>SUNNYVALE</City> 
    <State>CA</State> 
    <Zip>94089-1019</Zip> 
    <Country>US</Country> 
</Result> 
</ResultSet> 
SOAP的精简xml返回,其他信息,例如出错码等信息由Http协议头来承载。 

YouTube: 
请求消息: 
可以看到对于资源操作的URI定义也是参数的一部分。 
返回消息: 
<?xml version="1.0" encoding="utf-8"?> 
<ut_response status="ok"> 
    <user_profile> 
        <first_name>YouTube</first_name> 
        <last_name>User</last_name> 
        <about_me>YouTube rocks!!</about_me> 
        <age>30</age> 
        <video_upload_count>7</video_upload_count> 
    </user_profile> 
</ut_response> 
       自定义的类SOAP消息。 

Amazon: 
       请求消息: 
       https://Amazon FPS web service end point/?AWSAccessKeyId=Your AWSAccessKeyId 
      &Timestamp=[Current timestamp] &Signature=[Signature calculated from hash of Action and Timestamp] 
      &SignatureVersion=[Signature calculated from hash of Action and Timestamp] 
      &Version=[Version of the WSDL specified in YYYY-MM-DD format] &Action=[Name of the API] 
      &parameter1=[Value of the API parameter1] &parameter2=[Value of the API parameter2] 
      &...[API parameters and their values] 
       返回消息: 
       类似于SOAP的自有协议,消息体中包含了消息状态等附加信息。 

总结: 
       看了上面那么多网站的设计,总结一下主要有这么几种设计方式。 

请求消息设计: 
1. 基本符合REST标准方式:资源URI定义(资源.操作)+参数。这类设计如果滥用get去处理其他类型的操作,那么和2无异。 
2. REST风格非REST思想:资源URI定义+参数(包含操作方法名)。其实就是RPC的REST跟风。 
3. 类似于SOAP消息,自定义协议,以xml作为承载。(可扩展,例如鉴权,访问控制等),不过那就好比自己定义了一套SOAP和SOAP extends。大型的有实力的网站有的采取此种做法。 

响应消息设计: 
1.       REST标准方式,将Resource State传输返回给客户端,Http消息作为应用协议而非传输协议 
2.       以XML作为消息承载体,Http作为消息传输协议,处理状态自包含。 
3.       自定义消息格式,类似于SOAP,提供可扩展部分。 

作为遵循REST的理念来看我的选择是响应1和请求1的设计。



猜你喜欢

转载自blog.csdn.net/dongnan591172113/article/details/52102897