ONE RPC将客户端发送的参数,服务端发送的回复,都压缩在了一个二进制串里面,这样虽然可以解决双方的约定问题,但是有些不方便
首先,需要双方的压缩格式完全一致,一点不能有差错,因为出现了一点的错误,就会导致无法解压缩
其次,对于协议的修改,并不灵活,如果不是传输过程中的错误,而是因为客户端进行了相关的修改,但是没有告诉服务端,或者反之,就会导致传输的失败
这种使用的方式灵活性,灵活性太差了,就会导致每次只要一个小改动,就需要重新编写Stub程序
如果是沟通的话,还好说,如果提供了一个服务,有很多客户端都在用,现在有个需求,加了一个新字段,导致所有客户端都需要重写,加上这个字段,怎么办呢?
最后,原本的ONE RPC的设计师面向函数的,而非面向对象的,所以现在的面向对象的思想有所冲突\
所以,为了进行相对应的修改,我们需要加强RPC的规则
1.XML和SOAP
我们可以做一个通用类型的文本,只要能够拿到文本,就能知道其含义
常见的文本类的格式是XML ,如下的例子
<?xml version=”1.0″ encoding=”UTF-8″?>
<geek:purchaseOrder xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:geek=”http://www.example.com/geek”> <order> <date>2018-07-01</date> <className>趣谈网络协议</className> <Author>刘超</Author> <price>68</price> </order> </geek:purchaseOrder> |
XML的格式简单清晰,明了
可以一眼的读取出来
而且,即使顺序变了,也不影响客户端和服务端的解析
而且即使有多的字段,也没有问题,因为客户端即使拿到了对应的XML文件,只要不解析对应的字段就可以了
那么如何使用在RPC之中呢?
传输协议问题
如何使用,基于XML的著名通信协议就是SOAP,全程就是简单对象访问协议 Simple Object Access Protocol
使用XML编写简单的请求和回复消息,并且使用HTTP协议进行传输
SOAP将请求和回复挡在一个信封,并且使用HTTP进行发送
请求的格式如下
POST /purchaseOrder HTTP/1.1
Host: www.geektime.com
Content-Type: application/soap+xml; charset=utf-8
Content-Length: nnn
<?xml version=”1.0″?>
<soap:Envelope xmlns:soap=”http://www.w3.org/2001/12/soap-envelope” soap:encodingStyle=”http://www.w3.org/2001/12/soap-encoding”> <soap:Header> <m:Trans xmlns:m=”http://www.w3schools.com/transaction/” soap:mustUnderstand=”1″>1234 </m:Trans> </soap:Header> <soap:Body xmlns:m=”http://www.geektime.com/perchaseOrder”> <m:purchaseOrder”> <order> <date>2018-07-01</date> <className>趣谈网络协议</className> <Author>刘超</Author> <price>68</price> </order> </m:purchaseOrder> </soap:Body> </soap:Envelope> |
使用HTTP协议的POST方法,发送了一个格式为application/soapxml的XML正文,在这个HTTP协议中,说明对应的格式
协议的约定问题
因为服务开发出来了,是给陌生人用的,对于客户端来说,如何拿到上面的格式,当然,可以写文档,放在官方网站上,但是文档并不一定更新及时,而且文档并不一定严谨,所以,开发出了一种相对严谨的Web服务描述语言,WSDL,是一个XML文件
在这个文件中,定义一个order,和上面的XML对应起来
<wsdl:types>
<xsd:schema targetNamespace=”http://www.example.org/geektime”> <xsd:complexType name=”order”> <xsd:element name=”date” type=”xsd:string”></xsd:element> <xsd:element name=”className” type=”xsd:string”></xsd:element> <xsd:element name=”Author” type=”xsd:string”></xsd:element> <xsd:element name=”price” type=”xsd:int”></xsd:element> </xsd:complexType> </xsd:schema> </wsdl:types> |
作为一个描述层
然后呢,定义对应的message格式
<wsdl:message name=”purchase”>
<wsdl:part name=”purchaseOrder” element=”tns:order”></wsdl:part> </wsdl:message> |
最后,暴露一个端口
<wsdl:portType name=”PurchaseOrderService”>
<wsdl:operation name=”purchase”> <wsdl:input message=”tns:purchase”></wsdl:input> <wsdl:output message=”……”></wsdl:output> </wsdl:operation> </wsdl:portType> |
编写一个binding,然后将上面的信息绑定到SOAP请求的body里面
<wsdl:binding name=”purchaseOrderServiceSOAP” type=”tns:PurchaseOrderService”>
<soap:binding style=”rpc” transport=”http://schemas.xmlsoap.org/soap/http” /> <wsdl:operation name=”purchase”> <wsdl:input> <soap:body use=”literal” /> </wsdl:input> <wsdl:output> <soap:body use=”literal” /> </wsdl:output> </wsdl:operation> </wsdl:binding> |
对于某个服务,哪怕是个陌生人,都可以去调用获取到这个文件,哪怕这个文件比较复杂,难以看懂,也可以利用工具进行解析,然后进行调用
服务发现问题
如何发现服务,可以使用UDDI,统一描述,发现和集成协议,作为一个注册中心,服务提供方将上面的WSDL描述文件,发布到这个注册中心,注册完毕了,服务使用方可以查找到服务的描述,封装为本地的客户端使用
本章小结
对于原本的二进制RPC框架,缺点很多,格式要求严格,修改不方便,于是出现了基于文本的调用方式
SOAP,SOAP有着三大要素,协议约定用的WSDL,传输协议用HTTP,服务发现也能够UDDL
课后思考
1.对于HTTP协议,很多方法,但是SOAP只用了POST
2.基于文本的RPC虽然解决了二进制的问题,但是SOAP还是很复杂的,有更方便的吗?
1.SOAP不是只能通过HTTP传输,还有着SOAP binding
虽然http协议中有着post,get,head,put,delete等多种方法,但是一般post get足够使用,所以soap只支持post方法的差别应该在缺少get方法,get方法可以让浏览器直接跳转,post必须借助表单或者ajax才能提交,限制了soap在页面内获取数据或者提交数据
soap的协议里是支持get的,但是由于XML文件比较复杂,不太适合放在get请求的参数里面
所以一般采用post
2.SOAP的HTTP Binding支持很完整的Web Method. GET/POST都可以
而且只使用POST,不如GET请求那么方便
对于方便的协议,可以考虑restful协议