ONC RPC 存在哪些问题?
ONC RPC 将客户端要发送的参数,及服务要发送的回复,都压缩为一个二进制串,存在不便。
- 双方的压缩格式完全一致,一点都不能差,有一位不同都可能造成无法解压缩。
- 协议修改不灵活,业务发生改变时,修改了传递的参数,如果没有及时通知对方,重新生成双方的 Stub 程序,就会造成解压缩不成功。
- 版本问题。服务端提供的服务的参数格式为版本1,如果有一个客户端需要加一个字段,其余上线的客户端都要适配。
- ONC RPC 的设计不是面向对象的。
XML 与 SOAP
SOAP 采用文本格式 XML 进行传输。
- 格式不需要完全一致。比如不同字段可互换位置。
- 可灵活修改字段。比如有的客户端想增加一个字段,不需要该字段的客户端不解析便可。
- 面向对象,是更加接近用户场景的表达方式。
如何将 XML 用在 RPC 中?
1、传输协议问题
基于 XML 最著名的通信协议是 SOAP(Simple Object Access Protocol,简单对象访问协议),使用 XML 编写简单的请求和回复消息,并用 HTTP 协议传输。
SOAP 将请求和回复放在一个信封里,信封里的信分抬头和正文。
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 方法,给 www.geektime.com 发送一个格式为 application/soap + xml 的 XML 正文,从而下一个单,该订单封装在 SOAP 信封中,并表明这是一笔交易(transaction),订单详情已写明。
2、协议约定问题
双方的协议约定是什么样的?如何对服务进行描述,方便客户端调用?需要一种相对比较严谨的 Web 服务描述语言,WSDL(Web Service Discription Languages),也是一个 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>
- 编写 service。
<wsdl:service name="PurchaseOrderServiceImplService">
<wsdl:port binding="tns:purchaseOrderServiceSOAP" name="PurchaseOrderServiceImplPort">
<soap:address location="http://www.geektime.com:8080/purchaseOrder" />
</wsdl:port>
</wsdl:service>
WSDL 可使用工具自动生成。也有工具根据 WSDL 生成客户端 Stub。
3、服务发现问题
UDDI(Universal Description, Discovery and Integration),统一描述、发现和继承协议,是一个注册中心,服务提供方可将 WSDL 文件发布到该注册中心,客户端可查找到服务的描述,封装为本地的客户端进行调用。