WebService和编程语言中的类相似,它们都实现了一些功能,并且通过方法供给外部调用,不同的是WebService是部署在网络服务器上,而类在同一个进程空间里面。WebService部署在网络上,通过网络进行服务调用,只要遵循了访问协议,任何编程语言都可以访问服务,所以它是编程语言不相关的。

我们可以通过类文件知道一个类提供了哪些方法,那怎么知道WebService提供了哪些服务供外部调用呢?每一个WebService都有一个WSDL文件,WSDL全称Web Services Description Language(网络服务描述语言),WSDL有两个作用:

  1. 描述了WebService提供的服务,就像类里面的方法,包含名字、参数、返回值。
  2. 描述了访问服务的方法。

下面是一个WSDL的示例文件:


<?xml version="1.0" encoding="utf-8"?><!-- Published by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.7-b01  svn-revision#${svn.Last.Changed.Rev}. -->
<!-- Generated by JAX-WS RI at http://jax-ws.dev.java.net. RI's version is JAX-WS RI 2.2.7-b01  svn-revision#${svn.Last.Changed.Rev}. -->
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://example/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://example/" name="HelloWorldService">  <types> <xsd:schema> <xsd:import namespace="http://example/" schemaLocation="http://localhost:9090/HelloWorld?xsd=1"/> </xsd:schema> </types>  <message name="sayHelloWorld"> <part name="parameters" element="tns:sayHelloWorld"/> </message>  <message name="sayHelloWorldResponse"> <part name="parameters" element="tns:sayHelloWorldResponse"/> </message>  <portType name="HelloWorld"> <operation name="sayHelloWorld"> <input wsam:Action="http://example/HelloWorld/sayHelloWorldRequest" message="tns:sayHelloWorld"/>  <output wsam:Action="http://example/HelloWorld/sayHelloWorldResponse" message="tns:sayHelloWorldResponse"/> </operation> </portType>  <binding name="HelloWorldPortBinding" type="tns:HelloWorld"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>  <operation name="sayHelloWorld"> <soap:operation soapAction=""/>  <input> <soap:body use="literal"/> </input>  <output> <soap:body use="literal"/> </output> </operation> </binding>  <service name="HelloWorldService"> <port name="HelloWorldPort" binding="tns:HelloWorldPortBinding"> <soap:address location="http://localhost:9090/HelloWorld"/> </port> </service>
</definitions>

WSDL包含了五部分内容:

  • types
  • message
  • portType
  • binding
  • service

其中portType里面的内容描述了WebService提供的服务,上例中的portType内容可以翻译为Java类,如下:

 <portType name="HelloWorld">  ==> 对应类名<operation name="sayHelloWorld">  ==> 对应方法名......</operation> </portType>
//翻译后的portType内容
public class HelloWorld {public ... sayHelloWorld(...) {// ......}
}

可以看到sayHelloWorld方法中的参数和返回值使用了"...",这是因为通过portType无法直接得到参数和返回值,所以用“...”代替。至于具体的参数和返回值怎么获取,我们在后面讲解,姑且先当做void看待。现在知道了WebService提供的方法,要怎么调用它呢?还是得看WSDL,我们知道WebService是部署在网络上的,访问WebService就需要进行网络数据交互,网络数据交互需要通信协议。 WSDL中的binding部分描述了通信协议,WebService通常是HTTP + SOAP(Simple Object Access Protocol 简单对象访问协议)协议来进行数据交互,SOAP基于XML它被设计成在WEB上交换结构化的和固化的信息。本例中WebService也是采用HTTP+SOAP协议进行数据交互,本文中WSDL的binding内容如下所示:

 <!-- 为HelloWorld绑定通信协议 --><binding name="HelloWorldPortBinding" type="tns:HelloWorld"> <!-- HelloWorld 使用 http + soap 协议进行数据交互--> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document"/>      <operation name="sayHelloWorld"> <soap:operation soapAction=""/>  <input> <soap:body use="literal"/> </input>  <output> <soap:body use="literal"/> </output> </operation> </binding>   

下面是一个 HTTP+SOAP 示例:

POST URI HTTP/1.1
Accept: text/xml, multipart/related
Content-Type: text/xml; charset=utf-8
SOAPAction: "Action"
User-Agent: JAX-WS RI 2.2.7-b01  svn-revision#${svn.Last.Changed.Rev}
Host: localhost:9090
Connection: keep-alive
Content-Length: xxx<!-- SOAP协议 -->
<?xml version="1.0" encoding="utf-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">     <S:Body><!-- 内容由使用者定义 --><ns2:自定义元素 xmlns:ns2="http://example/">自定义元素内容</ns2:自定义元素></S:Body>
</S:Envelope>

可以看到HTTP+SOAP就是把SOAP放入HTTP的body部分使用POST发送给WebService服务器。SOAP协议的Body内容由使用者定义,WSDL为每个WebService方法的调用和返回定义了SOAP body格式也就是定义了一个XML元素,只要找到 WebService 方法对应的自定义元素,就能封装SOAP协议了。通过WSDL的portType 、message两部分内容可以找到方法对应的自定义元素,本例中这两部分内容如下所示:

<message name="sayHelloWorld"> <!-- 关联了一个sayHelloWorld元素 --><part name="parameters" element="tns:sayHelloWorld"/>
</message>
<message name="sayHelloWorldResponse"> <!-- 关联了一个sayHelloWorldResponse元素 --><part name="parameters" element="tns:sayHelloWorldResponse"/>
</message>    <portType name="HelloWorld"> <operation name="sayHelloWorld"> <!-- input关联了一个sayHelloWorld message--><input wsam:Action="http://example/HelloWorld/sayHelloWorldRequest" message="tns:sayHelloWorld"/>  <!-- output关联了一个sayHelloWorldResponse message--><output wsam:Action="http://example/HelloWorld/sayHelloWorldResponse" message="tns:sayHelloWorldResponse"/> </operation>
</portType>  

portType中的sayHelloWorld方法有一个input和output,input表示调用,output表示返回,input元素关联了一个message,本例中为“sayHelloWorld”,这个message关联了一个元素,本例中为sayHelloWorld,message关联的这个元素就是我们用来填充到SOAP body的元素了,同理output关联的元素为 “ sayHelloWorldResponse ” 。现在我们知道了调用 sayHelloWorld方法时使用
sayHelloWorld 元素填充Soap body,返回值使用 sayHelloWorldResponse 元素填充Soap body。但是我们还不知道这两个元素的具体定义,通过types部分我们可以知道这两个元素的具体定义,本例中的types定义如下:

 <types> <xsd:schema> <!--从http://localhost:9090/HelloWorld?xsd=1引入元素定义 --><xsd:import namespace="http://example/" schemaLocation="http://localhost:9090/HelloWorld?xsd=1"/> </xsd:schema> </types>

types从http://localhost:9090/HelloWorld?xsd=1引入了元素定义,引入的内容如下:

 <?xml version="1.0" encoding="utf-8"?><xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://example/" version="1.0" targetNamespace="http://example/">  <xs:element name="sayHelloWorld" type="tns:sayHelloWorld"/>  <xs:element name="sayHelloWorldResponse" type="tns:sayHelloWorldResponse"/>  <xs:complexType name="sayHelloWorld"> <xs:sequence> <!--  sayHelloWorld方法的参数 --><xs:element name="arg0" type="xs:string" minOccurs="0"/> </xs:sequence> </xs:complexType>  <xs:complexType name="sayHelloWorldResponse"> <xs:sequence> <!--   sayHelloWorld方法的返回值  --><xs:element name="return" type="xs:string" minOccurs="0"/> </xs:sequence> </xs:complexType> </xs:schema>   

可以看到sayHelloWorld元素包含一个类型为string的arg0元素,表示 sayHelloWorld 方法有一个string类型的参数。saysayHelloWorldResponse包含一个类型为string的return元素, 表示 sayHelloWorld 返回一个string类型的值。知道了参数和方法Webservice描述的方法就可以用Java完整的翻译出来,如下:

//WebService提供的服务
public class HelloWorld {public String sayHelloWorld(String arg0) {// ......}
}

知道了 sayHelloWorld 元素和 saysayHelloWorldResponse 元素的定义以后我们就知道怎么封装Soap了,调用 sayHelloWorld 并且传参数jack的Soap封装为:

 <?xml version="1.0" encoding="utf-8"?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><!-- 元素sayHelloWorld包含一个string类型的arg0元素表示参数  --><ns2:sayHelloWorld xmlns:ns2="http://example/"><!-- 传参jack --><arg0>jack</arg0></ns2:sayHelloWorld></S:Body></S:Envelope> 

返回时的Soap封装如下:

 <?xml version="1.0" encoding="utf-8"?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body> <!-- 元素 sayHelloWorldResponse 包含一个string类型的return元素表示返回值  --> <ns2:sayHelloWorldResponse xmlns:ns2="http://example/"><return>Hello, world, from jack</return></ns2:sayHelloWorldResponse></S:Body></S:Envelope> 

可以看到sayHelloWorld返回值是“Hello, world, from jack”。封装好Soap协议以后就可以往Webservice服务器发送协议了,但是我们目前还不知道Webservice的地址,通过WSDL的service部分可以获取Webservice的地址,本例中的service内容如下:

 <!-- WebService的地址从service部分获取 -->
<service name="HelloWorldService"> <port name="HelloWorldPort" binding="tns:HelloWorldPortBinding"> <!--  HelloWorld 的URI --><soap:address location="http://localhost:9090/HelloWorld"/> </port>
</service>   

地址http://localhost:9090/HelloWorld即为Webservice的服务器地址。另外HTTP头部有
SOAPAction需要填充,它来自 WSDL的portType的input和output,示例如下:

<input wsam:Action="http://example/HelloWorld/sayHelloWorldRequest" message="tns:sayHelloWorld"/>
<output wsam:Action="http://example/HelloWorld/sayHelloWorldResponse" message="tns:sayHelloWorldResponse"/>  

wsam:Action内容即是HTTP头部的SOAPAction。至此我没可以组装出完整的HTTP+SOAP,完整的调用协议内容如下:

 POST  /HelloWorld  HTTP/1.1Accept: text/xml, multipart/relatedContent-Type: text/xml; charset=utf-8SOAPAction: "http://example/HelloWorld/sayHelloWorldRequest"User-Agent: JAX-WS RI 2.2.7-b01  svn-revision#${svn.Last.Changed.Rev}Host: localhost:9090Connection: keep-aliveContent-Length: xxx  <?xml version="1.0" encoding="utf-8"?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><!-- 元素sayHelloWorld包含一个string类型的arg0元素表示参数  --><ns2:sayHelloWorld xmlns:ns2="http://example/"><!-- 传参jack --><arg0>jack</arg0></ns2:sayHelloWorld></S:Body></S:Envelope>  

完整的返回协议如下:

 HTTP/1.1 200 OKDate: Fri, 17 May 2019 08:34:13 GMTTransfer-encoding: chunkedContent-type: text/xml; charset=utf-8<?xml version="1.0" encoding="utf-8"?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body> <!-- 元素 sayHelloWorldResponse 包含一个string类型的return元素表示返回值  --> <ns2:sayHelloWorldResponse xmlns:ns2="http://example/"><return>Hello, world, from jack</return></ns2:sayHelloWorldResponse></S:Body></S:Envelope> 

虽然WebService的底层很复杂,但是大多数编程语言都有现成的框架帮助我们完成底层的细节,具体的我们在编写WebService时通常只用创建一个类并且实现类的一些方法, 框架会根据类自动生成WSDL 。WebService的调用也很简单,框架可以根据WSDL生成一个类,我们只需实例化对象然后调用方法获取返回值,和使用普通的类没什么两样。

WSDL是Webservice中最重要的内容,理解WSDL对使用Webservice和调试Webservice非常有用,
它包含五部分内容,通过上文的学习我们可以总结出每个部分的功能:

  • service,提供了WebService的访问地址 。
  • portType,定义了WebService提供的服务。
  • binding,定义了WebService通信协议 。
  • message,定义了每个服务调用的和返回的格式,常通过引用一个自定义元素,由自定义的元素 (element) 描述格式。
  • types,定义了message引用的各种自定义元素(element)。

本文描述的WSDL使用Document literal wapped 格式的协议,它还支持RPC literal/encode 协议,关于两种协议的区别和各自的应用场景会在后面的文章中讲解。

WebService原理浅析相关推荐

  1. Python标准库queue模块原理浅析

    Python标准库queue模块原理浅析 本文环境python3.5.2 queue模块的实现思路 作为一个线程安全的队列模块,该模块提供了线程安全的一个队列,该队列底层的实现基于Python线程th ...

  2. Python标准库threading模块Condition原理浅析

    Python标准库threading模块Condition原理浅析 本文环境python3.5.2 threading模块Condition的实现思路 在Python的多线程实现过程中,在Linux平 ...

  3. 第一篇: 词向量之Word2vector原理浅析

    第一篇: 词向量之Word2vector原理浅析 作者 Aroundtheworld 2016.11.05 18:50 字数 1353 阅读 5361评论 1喜欢 9 一.概述 本文主要是从deep ...

  4. SPI及其工作原理浅析

    说明.文章摘自:SPI协议及其工作原理浅析 http://bbs.chinaunix.net/thread-1916003-1-1.html 一.概述. SPI, Serial Perripheral ...

  5. .NET1.1中预编译ASP.NET页面实现原理浅析[1]自动预编译机制浅析

    .NET1.1中预编译ASP.NET页面实现原理浅析[1]自动预编译机制浅析 .NET1.1中预编译ASP.NET页面实现原理浅析[1]自动预编译机制浅析 作者:&;nbsp来自:网络 htt ...

  6. LinkedList 的实现原理浅析

    转载自 LinkedList 的实现原理浅析 LinkedList内部结构 查看LinkedList的源码,发现其继承自AbstractSequentialList,实现了List,Deque,Clo ...

  7. Spring AOP原理浅析及入门实例

    上篇问题及Spring AOP实现原理浅析 上篇说了一个AOP编程问题,那是一个错误的AOP案例.它的错误在A类中,再次粘贴A类代码: @Componentpublic class AImpl imp ...

  8. webservice 原理

    webservice 原理 1.soap协议,其实就是用http协议来传输xml格式的数据,可以post,get.一般有post. 2.服务端有:本地程序代码(也不是dll)和xml格式的文件用来描述 ...

  9. redis单线程原理___Redis为何那么快-----底层原理浅析

    redis单线程原理 redis单线程问题 单线程指的是网络请求模块使用了一个线程(所以不需考虑并发安全性),即一个线程处理所有网络请求,其他模块仍用了多个线程. 1. 为什么说redis能够快速执行 ...

  10. 沉淀,再出发:docker的原理浅析

    沉淀,再出发:docker的原理浅析 一.前言 在我们使用docker的时候,很多情况下我们对于一些概念的理解是停留在名称和用法的地步,如果更进一步理解了docker的本质,我们的技术一定会有质的进步 ...

最新文章

  1. 基于JSP/SERVLET学生管理系统
  2. 机器学习如何改变大数据管理
  3. 如何测试一个网页登陆界面
  4. 不止性能优化,移动端 APM 产品研发技能
  5. leetcode100. 相同的树(dfs)
  6. (转) POJO和javabean的异同
  7. PHP程序员测试题及答案
  8. upupoo怎么设置本地html文件,关于Upupoo自定义元素教程
  9. 从零开始开发Python程序(五)—— 把文字排版成一张图片
  10. CAD直线和平面投影
  11. POJ - 3258 River Hopscotch 二分
  12. 缓冲区,缓存,fflush(stdin)如何使用?
  13. ftp 服务器管理工具,5款最好用的ftp 服务器管理工具
  14. 软件测试人员的年终绩效考核怎么应对
  15. 有机酸膜分离之柠檬酸生产应用反渗透技术
  16. 【杂谈】关于个人档案的机要邮寄
  17. 这3个BT下载工具,可替代迅雷,总有一个适合你
  18. 28 电子商务风险控制
  19. 图书馆信息管理系统(毕业设计)
  20. 习题 9.5 建立一个对象数组,内放5个学生的数据(学号、成绩),设立一个函数max,用指向对象的指针作函数参数,在max函数中找出5个学生中成绩最高者,并输出其学号。

热门文章

  1. mysql数据库闪退
  2. 华为hs8145v5刷机包_华为hs8145v5刷机包_华为P40 Pro(ELSAN00/TN00)官方11.0.0.155固件卡刷包强刷包救砖包...
  3. 你还在对着手机干唱?k歌神器挑选法则
  4. 海创软件组-20200614-用户自定义工程认证调查模板-大创项目申报书
  5. Simulink汽车动力学仿真
  6. C# 调用dll文件
  7. 十代主板改win7_微星b460主板装win7系统及bios设置教程(支持十代usb驱动)
  8. snagit 9.0注册码
  9. Axure RP9教程大全
  10. verilog语法记录(一)