基本概念

1. rest和rpc架构的概念

REST架构:
方法信息(method information)都在HTTP方法(HTTP method)里.

面向资源的架构(ROA): 作用域信息(scoping information)都在URI里.

如果一个系统架构的实现, 完全满足以上两条,则可以认为是一个纯正的rest架构, 如果都不满足,则是一个典型的rpc架构。通常来说,更常见的可能是一种rest-rpc 混合架构.

作者也指出:
许多只读的Web服务,尽管它们起初也许是按RPC风格设计的,但它们都可称得上是完全REST式和面向资源的! 但是,如果该服务允许客户端修改数据的话,就会出现客户端所使用的HTTP方法与真正的方法信息不一致的情况——这样它就不具备REST式服务的特征了。 像这样的服务,我称之为REST- RPC混合服务。


RPC式架构:方法信息和作用域信息都在信封(envelope)或报头(headers)里。 具体采用哪种信封,并不影响这里的分类,不过HTTP是一种常见信封格式. RPC将服务器看作是由一些过程组成,客户端调用这些过程来执行特定的任务。这种特定决定了rpc调用的高耦合性,不过就应用开发的角度来说,很多人不会去关心这个问题。

分布式对象架构:分布式对象架构将服务器看做远程对象的组合,通过代理调用远程对象来掩饰本地对象和远程对象的差别。分布式对象结构的主要缺点是粒度的控制问题,另外某种意义上分布式对象结构依然是rpc风格的,只不过做了更好的掩饰。

2. big soap webservice中的rpc和document的概念

顺手补习一下 ws * 中的rpc和document的概念。

常见两种编码绑定方式, rpc风格和document风格, 虽然后者理论上号称是非rpc方式的面向消息的封装,并具有一些理论上的优点,但实际情况仍然是rpc方式。

可以从xml文件的结构来看两种模式的差异

rpc风格
请求包

<?xml version="1.0" ?>
<soapenv:Envelope
      
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
      xmlns:xsd
="http://www.w3.org/2001/XMLSchema"
      xmlns:ns1
="http://item.service.soap.soajava.packt.com/">
  
<soapenv:Body>
    
<ns1:insert> // method name bingding
    
<arg0> // parameter
      
<code>XY</code>
      
<description>xy desc</description>
      
<id>26</id>
    
</arg0>
    
</ns1:insert>
  
</soapenv:Body>
</soapenv:Envelope>

一个rpc调用总是由4部分组成
  • A remote address
  • A method (or operation) name
  • A sequence of parameters
  • A synchronous response
这4部分基本和一个程序语言的方法调用一致。
rpc风格的wsdl文件描述
      <message name="insert">
         
<part name="itemParam" type="tns:item"></part>
         
<part name="categoryParam" type="xsd:string"></part>
      
</message>
      
<message name="insertResponse">
         
<part name="return" type="tns:outcome"></part>
      
</message>
      
<portType name="ItemWs">
         
<operation name="insert" parameterOrder
                                     "itemParam categoryParam"
>
            
<input message="tns:insert"></input>
            
<output message="tns:insertResponse"></output>
         
</operation>
      
</portType>
      
<binding name="ItemWsPortBinding" type="tns:ItemWs"> 
         
<soap:binding style="rpc" 
                    transport
="http://schemas.xmlsoap.org/soap/http">
         
</soap:binding>
         
<operation name="insert">
            
<soap:operation soapAction=""></soap:operation> 
            
<input> 
               
<soap:body use="literal" namespace
                       "http://item.service.soap.soajava.packt.com/"
>
               
</soap:body> 
            
</input> 

Document 风格
请求包
  <ns1:itemInsertRequestParam> // no method call here
            
<category>A</category>
            
<item>
               
<code>XY</code>
               
<description>xy desc</description>
               
<id>26</id>
            
</item>
  
</ns1:itemInsertRequestParam>

虽然看起来差别不大,但是此处已经没有所谓明显的方法调用特征,无方法名和参数绑定,即请求包是以所谓document为处理核心的,而document可以理解为一种resouce或者message。(呵呵,有点自欺欺人)。

更大的差别在wsdl的描述上

  <message name="insert"> 
         
<part element="tns:itemInsertRequestParam"
                  name
="itemInsertRequestParam"></part>  // no type attribute here.
 
</message>
      
      
<binding name="ItemWsPortBinding" type="tns:ItemWs">
         
<soap:binding style="document"
message里只包含一个part,也不再使用type熟悉申明。据说这样的差别决定了可以用xsd对文档进行校验(我没完全明白)。


虽然实际上rpc和document差别不大,但是理论上存在2个重大差异
1. document风格不直接和方法绑定,所以方法变化时,比如增加一个属性时,不一定会影响客户端代码。
2. document风格能提供对文档的校验模式。

但实际上, webservice中的 document风格绑定,其实还是rpc的。从这可以看出big web service是多么的无聊。

实际应用中,这2种风格的差别会引起很多问题, 一些传统的老旧应用基本是rpc风格的,而某些应用和webservice实现则只提供document的支持。这会部分导致兼容性问题,虽然理论上,新的总是兼容旧的,但实际问题多多。

顺便说一个实际工作中碰到的问题,在使用domino7将服务发布成document风格的web service时,我们有时候(牛就牛在这有时候)会出现服务调用乱窜的问题, 客户端提交的服务调用会乱窜到同参数的其他服务中,充分体现了document风格不以方法名绑定的实质,nnd。

另外,是否正是因为soap这种先天性的rpc架构缺陷,导致了必然的兼容性和复杂性问题?

为什么要使用rest架构

对此问题我其实长期以来一直存在一个本质的误解。 我之所以喜欢用restful 的web service,其实更直接的原因是我实在讨厌soap的big web service。 使用rest我至少得到了2个好处。
1. 开发效率和执行效率的显著提高
2. 回避了兼容性问题,特别是异构系统间。

好吧,但是象ror那样,把所有内容都发布成了CRUD的操作的rest,我还是一直比较反感的,实在看不出其中的好处。我一直觉得,远程服务应该是比较大粒度的东西,不应该将所有的资源都服务化。 而旺财同学曾经给我看过infoq上一篇文章,关于rest的那10个问题,看完以后我还是继续迷糊,好像一个问题都没有解释清楚。

不过今天突然明白了。rest的意义在于通过将数据操作的资源化,给客户端的使用提供了足够的灵活性,这是传统结构难以比拟的。这其实是一个视角变换的问题。

静态网页比动态的bbs更容易被检索使用也是由于这种信息的资源化,资源化的结果是给客户端的玩法提供近乎无限的可能性。rest其实是一种以客户端使用为主要核心的结构。


其实想想自己平时在应用开发中对数据的操作也能对应起来。一般来说做一个业务系统开发,对数据我会干2件事。

1. 使用技巧实现一个万能dao,或者通过模板工具,将所有数据表映射到对象并创建对应的CRUD操作甚至关联操作。

这样做的目的并不在于系统中所有的表都需要做crud操作,而是试图把对数据库的操作释放为标准的对象操作,屏蔽掉数据库操作,提高程序员操作的灵活性。

2. 对应非CRUD的操作, 则重新编写专门的代码实现。

而对应的 REST 的 过程

1. 将数据的CRUD操作资源化发布。

   可以考虑c/s结构的开发, 如果未有此种资源化会增加客户端和服务器多少工作量?

2. 对于复杂的操作需求,编写专门服务实现。
   这个操作有可能是rpc风格的。
   

这2种做法基本一致, 都是按2,8 原则对粗粒度和细粒度进行组合。 而我之前的迷糊,其实来源于以往分布式对象架构经验的困扰,EJB/RMI方面的苦难经历已经给我们洗脑,分布式结构,细粒度总是不好的,灵活总是难以控制的,所以我们习惯于限制客户端的可操作性。

REST的架构, 某种意义应该理解为客户端应用导向的架构,关心的是能给予客户端更多的灵活性而不是更多的限制。

服务和客户的对应关系,总是1对n的关系。 从这个角度看,rest是天生更适合SOA的, 比SOAP 要合适的多。

但是如何有效又简洁而且便宜的解决安全问题? 这个还需要继续研究。