当前位置: 首页 > 科技观察

咖啡馆的故事:FTP,RMI,XML-RPC,SOAP,REST一气呵成

时间:2023-03-17 17:15:56 科技观察

周末的咖啡馆有点奇怪,一群人围着几个老头聊天。“告诉我,你那时候还没有HTTP和JavaScript,你到底是怎么让这些机器上的程序‘对话’的?”ftp老哥喝了一口咖啡说:“很简单,A机器通过我,也就是ftp,上传一个文件到B机器的指定路径,然后让rexec调用B机器上的程序.这个程序是程序员写的,可以读取FTP目录下的文件,执行业务逻辑。”“什么是rexec?“就是从一台机器远程执行命令到另一台机器!”老头rexec怒道,他虽然没有ftp那么出名,但也没有人知道![remote_host][command]“切!不可能骗人的,怎么会用这么蠢的办法!”人群中传来不屑的声音。ftp和rexec对视一眼,苦笑起来。这些程序员怎么也想不到,居然有系统可以做到这一点。早些年,还是个真实的故事,FTP招呼telnet一起喝咖啡,不再说话。一下子,抛弃了三个老头。只听JavaRMI说:“所有的程序本质上都是函数调用,而函数调用在一个进程中是很自然的。”如果是跨机器、跨进程呢?如果一台机器上的函数可以调用另一台机器上的函数调用本地方法会是什么样子呢?”CORBA笑道:“哈哈,画面太美了,无法想象。”人群中有人问:“调用远程方法就像调用本地方法?如何?也许吧?”JavaRMI说:“这个概念其实极其简单。无非就是自动生成client-sideproxy和server-sideproxy。这两个代理完成了很多又脏又累的工作,比如:网络通信,参数序列化。....”CORBA继续说:“神奇的是这两个代理,我们称之为Stub(客户端代理)和Skeleton(服务器代理)。这个Stub代理提供与服务器相同的接口。客户端程序只要调用它,就会将请求发送给服务器端的Skeleton代理进行处理。所以对于客户端程序来说,网络是不可见的,就像调用本地方法一样。”JavaRMI说:“是的,我们称这个方法为RPC。众人惊呼:“这个RPC真是太好了,Stub和Skeleton代码都可以自动生成,我们搞定后,马上就可以开始编程了,底层什么都不用关心。””JavaRMI说:“底层可以用二进制协议,性能应该不会太好!”众人再次欢呼:“太好了!”那边的ftp老头警告:“大家小心点,注意平台绑定,要用JavaRMI吗?抱歉,客户端和服务端都必须使用Java,而且都得安装Java虚拟机。Python,C#,没办法,想都别想。”Telnet接着说:“更重要的是,客户端和服务器绑定的很紧,服务器上的改动必须重新生成Stub和Skeleton。”没想到这几个老家伙眼睛都亮了。“什么?这也太不讲道理了!”人群再次怒吼着冲向三位老者。只见ftp老者在纸上写道:比如有这么一个接口,可以根据用户ID查找用户信息。publicinterfaceUserServiceextendsRemote{publicUserfindUser(intid)throwsRemoteException;}利用JavaRMI工具,可以生成Stub和Skeleton,客户端拿到Stub后就可以愉快的编程了,至于UserService的具体实现代码,客户端不用管。过了两天,一个客户端要求给这个接口增加一个新的方法:通过名字查找用户publicUserfindUser(Stringname)throwsRemoteException;sorry,需要重新生成新的Stub和Skeleton,所有的客户端都会受到影响,即使你不这样做完全需要新方法。众人感叹,这RPC真是烦死人了!有没有办法让服务端独立改变而不影响客户端,或者尽量不影响客户端?XML-RPCThinking背后有一个人,他刚学XML,他觉得既然XML有这么强的描述能力,能不能用XML来描述一个方法调用和参数呢?比如服务器端有个接口是getUser,需要提供的参数是用户ID。说明:然后将这个XML通过HTTPPost发送给服务器,服务器解析,得到方法名和参数值,调用真正的方法,将结果以XML形式返回,客户端接收后解析即可获取它成功了。想到这里,他喊道:“不要生成任何Stub和Skeleton代理,直接使用HTTP和XML就好了。”被他奇怪的想法吸引,围观的人群再次围了过来,发出一阵呜??咽声。小伙子画了一张处理过程图:有人问:“返回的数据格式可能比较复杂,怎么表达。”小伙子说:“这就是XML的强项,如图所示,int类型还可以有double、boolean、string等类型,甚至可以定义structure。”对于XML来说,这样的结构是小菜一碟。”这样一来,客户端和服务器就变得松耦合了。如果服务端想增加一个新的接口,客户端不需要做任何改动。我打算称它为XML-RPC,”年轻人说。“这是一个很棒的方法!”人群开始骚动起来,“让我们都使用XML-RPC!”SOAP“小伙子,你叫什么名字?”热情的人群平静地问道。“戴夫温纳,有什么事吗?嗯,你的名字真好,天生的赢家,有没有兴趣和微软一起开发一个新的RPC标准?”“新标准?我的XML-RPC已经很完美了,简单易用。”“不不不,还缺很多东西,最要命的是,客户端和服务器之间没有正式的协议,都是口头协议或者文件协议吧?”戴夫温纳点头。“想一想,如果我们用XML描述一个服务器提供的接口,那么任何程序只要读取XML文件就可以知道接口的方法名和参数名。”DaveWiner再次点头。“还有,你的XML-RPC只支持HTTP,我们的新标准可以支持任何协议,HTTP、SMTP、TCP、UDP……都可以。”“我还是觉得HTTP***!”“想想看,如果我们的新协议完成了,所有的B2B电子商务系统都可以使用这套协议进行自动通信,这是一个怎样的世界啊!你想喝咖啡吗?”一辈子破咖啡馆,还是想和微软一起改变世界?”一年后,DaveWiner的新协议出来了,不,这其实是一套协议:WSDL:用来描述一个服务的接口和参数。.....UDDI:实现服务注册和发现SOAP:类似于XML-RPC,但更规范、更正式、更复杂……它们之间的关系如图:微软的.NET战略的推出恰逢其时,WebService的宣传铺天盖地:只要用WSDL定义接口,就可以选择任何语言来实现!Java、Python,甚至C语言都可以。当然我们的VisualStudo,C#和它的集成度更高。好的欢迎。人们蜂拥而至。几年后,DaveWiner再次来到咖啡馆。这次他选了一个角落坐下,点了杯咖啡,静静地听大家聊天。“你知不知道微软这么蠢,那个SOAP实在是太难用了!”“对对对,罗嗦,罗嗦,罗嗦。你看我每次发SOAP请求多麻烦:"1001"这是什么东西,返回值也是一样罗嗦的XML,解析起来真是费劲。”“是啊,不借助可视化工具,根本无法使用。DaveWiner一边喝着咖啡一边想,没办法,这个XML是这样的,但是我们的SOAP是不是有点过分了?“我看这就是那些大厂商为了赚钱而做的,都是为了卖他们的软件,一点都不实用!”“让我们回到最简单的HTTP调用!”有人提议。比如你想获取一个用户的信息,你可以调用这样一个APIhttp://xxx.com/getUser?id=1001"服务器还得返回又臭又长的XML吗?"“不,我们可以用JSON作为一种数据格式,它简洁紧凑,对JavaScript很友好,处理起来也很方便。”大家都同意。和原来的XML-RPC一样,都是把服务端看成函数的集合,然后由客户端调用。JavaRMI是通过Stub/Skeleton代理,而XML-RPC是通过XML。一个叫Roy的小哥提醒道。“那是不错,服务端不就是一堆函数吗?”有人说。“各位,换个思路,不要把它们当作功能,而是当作资源(Resources),试着从动词换成名词。”听到罗伊的新奇想法,一群人再次围了过来。“名词?资源?”“是的,比如用户、学生、订单等,自然可以用uri来表示。”“有意思,这些资源怎么操作?”“HTTP方法GET、POST、DELETE、PUT、HEAD...可以用作动词。”罗伊说。“我妈,你居然把HTTP方法想成增删改查。”说了这么多,大家觉得这个方法还是挺简单的,充分利用了HTTP的特性,只要脑子里不看服务器端就行。变成一个函数,不过是一堆名词资源就可以了。“这个方法叫什么名字?”“REST风格的API!”“这个RESTful看起来不错,我们为什么不试试呢?”“试试看!不行就找这个罗伊算账!”【本文为专栏作家“刘鑫”原创稿件,转载请通过作者微信获取授权公众号coderising】点此查看作者更多好文