7.Web服务中Soap消息的相关知识
当你已经了解Xml的知识后,我们就来较为详细的探讨一下Web Services中的Soap消息。这里我们是基于Visual Studio.Net2005中建立的WebService和前面我们所举的例子中有关的WebService。好了我们开始来详细探讨吧!
一、Soap协议知识
1、Soap是什么
Soap是简单对象访问协议。在1998年就已经诞生,当时只是当作RPC机制(远程过程调用)。然而人们发现Soap可以用于更广泛的用途,因此在今天的Soap1.1规范中不再有过多的限制。但是在当时缺少一种能够通用的数据描述语言,而使Soap不能得到普遍的认同。如今随着Xml的诞生和发展并于Soap的完美结合,使Soap得到了大多数人的青睐,同时也使Web Services得到了推广。
Soap和Http一样都是一种应用级的协议,使用它可在不同的应用程序之间方便的交换数据。Soap除了可以基于Http协议外,还可以其他的任何传输协议实现应用程序到应用程序的通信。
2、Soap的结构
正如在《Web服务初探:用Demo学Web服务系列(7)——XML的相关知识》中我们所举的例子那样,Soap消息是由一个信封组成,这个信封定义了消息的总体结构。包含在信封中的是消息头信息(可选)和消息体信息(必选)。消息头和消息体并没有在Soap规范中定义,这些信息是特定于使用Soap消息的系统的。如果需要使用错误消息,则错误消息被包含在消息体中。
下面给出一个简单的Soap消息例子:
Soap消息的创建者可以把任意元素放在这个部分,这个部分组成了Soap消息的消息头信息。在处理Web Services时,这个部分也许是完全没有必要的。即便如此,我们也还是要了解Soap消息头中的两个有用的属性:指定消息头所瞄准的端点类型(artor属性),这个属性我们很少会用到,所以在这里就不多说了;消息头是否必须被处理(mustUnderstand属性),当值为“1”或者是“true”时,则消息头就必须被Web Services处理。关于消息头的使用我们在前面的Demo中已经讲解和使用过了,那么上次的Demo中我们所产生的Soap消息头是什么样子的呢,请看下面的例子:
综上可以看出,消息头信息对于保存和消息的语义不是直接相关的上下文信息是很有用的。
(2)、Soap消息体部分
和Soap消息头部分一样,Soap消息体的内容完全取决于在被瞄准的Web Services的语义中指定的消息定义。说确切点就是,内容是由和Web Services相关的WSDL文档定义的。
下面我们分别来看在前面的随笔中的Demo中每个方法所产生的Soap消息内容如下:
3、Soap中的Namespace
值得一提的是,在所有的Soap消息中都能看到Namespace,这个到底是有什么用处的呢?我们知道在Xml中有很多描述数据的标记,然而有时候同一个标记在不同的地方有不同的意义,因此为了区分它们我们就必须为相同的标记表示的不同的含义指定Namespace,而指定Namespace也并不是随便的一个值,必须是类似于虚拟地址的书写格式,如:Namespace="http://www.microsoft.com/MyService",这里的网址不一定非要是可以连接的。
二、WSDL文档
1、WSDL扩展
如果不和具体的协议一起使用,WSDL定义就没有那么有用了,你可以自己定义协议,也可以使用Soap协议和Http协议这两个协议也就足够了。
2、什么是WSDL文档
如果单独提及WSDL这个名词,它常常表示用于描述Web服务的语法规范。但如果同时提到某个Web Services,那它就表示这个Web Services的说明文档。
WSDL文档是对一个Web Services的位置、协议和接口详细且明确的说明。它由Web Services的开发者提供,现在已经有能够根据Web Services的代码自动生成WSDL文档的工具了。虽然如此,Web Services的开发者也可以自己手工编写,因为WSDL文档也是Xml文件,只是编写的时候必须严格遵守WSDL规范的要求。
3、WSDL文档结构
WSDL文档的根元素是<definitions>,其中包括多种子元素。这些子元素总体上可以分为两类:一类位于文档的前半部分,它们构成Web Services的“具体说明”。抽象部分是独立于平台和程序语言的方式来描述Web Services,比如Web方法的参数类型;后一部分指定Web Services的具体内容,比如传输协议。
抽象定义部分包括三个元素:Types,独立于机器和程序语言的类型定义。Messages,包含方法参数(输入和输出分开)或消息文档说明。PortTypes,使用Messages部分的消息定义来描述方法的签名(操作名称、输入参数和输出参数)。在PortTypes中具体说明时又包含两个元素:Bindings,指定PortTypes部分中每个操作的绑定信息。Services,指定每个绑定的Port地址。
抽象定义和具体说明,既是有一定的各自独立性,又有一定的相互关联性。还要说明的是在一个WSDL文档中可以没有Types部分,但如果有那么就只能有一个。
下面就来看看我们在前面的随笔中的Demo中所产生的WSDL文档,原文件如下:
学会读WSDL文档有助于你在调用他人开发的Web Services时的理解和使用,WSDL文档就如同对Web Services使用的说明书,这就是我们为什么要讲解WSDL文档的一些内容的原因。
一、Soap协议知识
1、Soap是什么
Soap是简单对象访问协议。在1998年就已经诞生,当时只是当作RPC机制(远程过程调用)。然而人们发现Soap可以用于更广泛的用途,因此在今天的Soap1.1规范中不再有过多的限制。但是在当时缺少一种能够通用的数据描述语言,而使Soap不能得到普遍的认同。如今随着Xml的诞生和发展并于Soap的完美结合,使Soap得到了大多数人的青睐,同时也使Web Services得到了推广。
Soap和Http一样都是一种应用级的协议,使用它可在不同的应用程序之间方便的交换数据。Soap除了可以基于Http协议外,还可以其他的任何传输协议实现应用程序到应用程序的通信。
2、Soap的结构
正如在《Web服务初探:用Demo学Web服务系列(7)——XML的相关知识》中我们所举的例子那样,Soap消息是由一个信封组成,这个信封定义了消息的总体结构。包含在信封中的是消息头信息(可选)和消息体信息(必选)。消息头和消息体并没有在Soap规范中定义,这些信息是特定于使用Soap消息的系统的。如果需要使用错误消息,则错误消息被包含在消息体中。
下面给出一个简单的Soap消息例子:
1
<?xml version="1.0" ?>
2
<soap:Envelop xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
3
<soap:Header>
4
<!-- 这里是消息头内容 -->
5
</soap:Header>
6
<soap:Body>
7
<!-- 这里是消息体内容 -->
8
</soap:Body>
9
</soap:Envelop>![]()
(1)、Soap消息头部分
2

3

4

5

6

7

8

9


Soap消息的创建者可以把任意元素放在这个部分,这个部分组成了Soap消息的消息头信息。在处理Web Services时,这个部分也许是完全没有必要的。即便如此,我们也还是要了解Soap消息头中的两个有用的属性:指定消息头所瞄准的端点类型(artor属性),这个属性我们很少会用到,所以在这里就不多说了;消息头是否必须被处理(mustUnderstand属性),当值为“1”或者是“true”时,则消息头就必须被Web Services处理。关于消息头的使用我们在前面的Demo中已经讲解和使用过了,那么上次的Demo中我们所产生的Soap消息头是什么样子的呢,请看下面的例子:
综上可以看出,消息头信息对于保存和消息的语义不是直接相关的上下文信息是很有用的。
(2)、Soap消息体部分
和Soap消息头部分一样,Soap消息体的内容完全取决于在被瞄准的Web Services的语义中指定的消息定义。说确切点就是,内容是由和Web Services相关的WSDL文档定义的。
下面我们分别来看在前面的随笔中的Demo中每个方法所产生的Soap消息内容如下:
1
<!-- 这里是Login的Soap消息,在运行前面Demo中的MyServiceClass时会看见此请求和响应的Soap消息 -->
2
POST /WebServicesDemo/MyServiceClass.asmx HTTP/1.1
3
Host: localhost
4
Content-Type: application/soap+xml; charset=utf-8
5
Content-Length: length
6![]()
7
<?xml version="1.0" encoding="utf-8"?>
8
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
9
<soap12:Header>
10
<MyServiceClassHeader xmlns="http://tempuri.org/">
11
<UsN>string</UsN>
12
<PaW>string</PaW>
13
</MyServiceClassHeader>
14
</soap12:Header>
15
<soap12:Body>
16
<Login xmlns="http://tempuri.org/" />
17
</soap12:Body>
18
</soap12:Envelope>
19
<!-- 上面的是请求Soap消息 -->
20![]()
21
HTTP/1.1 200 OK
22
Content-Type: application/soap+xml; charset=utf-8
23
Content-Length: length
24![]()
25
<?xml version="1.0" encoding="utf-8"?>
26
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
27
<soap12:Body>
28
<LoginResponse xmlns="http://tempuri.org/">
29
<LoginResult>string</LoginResult>
30
</LoginResponse>
31
</soap12:Body>
32
</soap12:Envelope>
33
<!-- 上面是响应Soap消息 -->

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

1
<!-- 这里是SelectUser的Soap消息,在运行前面Demo中的MyServiceClass时会看见此请求和响应的Soap消息 -->
2
POST /WebServicesDemo/MyServiceClass.asmx HTTP/1.1
3
Host: localhost
4
Content-Type: application/soap+xml; charset=utf-8
5
Content-Length: length
6![]()
7
<?xml version="1.0" encoding="utf-8"?>
8
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
9
<soap12:Body>
10
<SelectUser xmlns="http://tempuri.org/">
11
<UserName>string</UserName>
12
</SelectUser>
13
</soap12:Body>
14
</soap12:Envelope>
15
<!-- 上面是请求Soap消息 -->
16![]()
17
HTTP/1.1 200 OK
18
Content-Type: application/soap+xml; charset=utf-8
19
Content-Length: length
20![]()
21
<?xml version="1.0" encoding="utf-8"?>
22
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
23
<soap12:Body>
24
<SelectUserResponse xmlns="http://tempuri.org/">
25
<SelectUserResult>
26
<xsd:schema>schema</xsd:schema>xml</SelectUserResult>
27
</SelectUserResponse>
28
</soap12:Body>
29
</soap12:Envelope>
30
<!-- 上面是响应Soap消息 -->
其中的以黄色底显示的部分在Soap消息真正使用时会用实际的相应数据类型值所替代。
2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

3、Soap中的Namespace
值得一提的是,在所有的Soap消息中都能看到Namespace,这个到底是有什么用处的呢?我们知道在Xml中有很多描述数据的标记,然而有时候同一个标记在不同的地方有不同的意义,因此为了区分它们我们就必须为相同的标记表示的不同的含义指定Namespace,而指定Namespace也并不是随便的一个值,必须是类似于虚拟地址的书写格式,如:Namespace="http://www.microsoft.com/MyService",这里的网址不一定非要是可以连接的。
二、WSDL文档
1、WSDL扩展
如果不和具体的协议一起使用,WSDL定义就没有那么有用了,你可以自己定义协议,也可以使用Soap协议和Http协议这两个协议也就足够了。
2、什么是WSDL文档
如果单独提及WSDL这个名词,它常常表示用于描述Web服务的语法规范。但如果同时提到某个Web Services,那它就表示这个Web Services的说明文档。
WSDL文档是对一个Web Services的位置、协议和接口详细且明确的说明。它由Web Services的开发者提供,现在已经有能够根据Web Services的代码自动生成WSDL文档的工具了。虽然如此,Web Services的开发者也可以自己手工编写,因为WSDL文档也是Xml文件,只是编写的时候必须严格遵守WSDL规范的要求。
3、WSDL文档结构
WSDL文档的根元素是<definitions>,其中包括多种子元素。这些子元素总体上可以分为两类:一类位于文档的前半部分,它们构成Web Services的“具体说明”。抽象部分是独立于平台和程序语言的方式来描述Web Services,比如Web方法的参数类型;后一部分指定Web Services的具体内容,比如传输协议。
抽象定义部分包括三个元素:Types,独立于机器和程序语言的类型定义。Messages,包含方法参数(输入和输出分开)或消息文档说明。PortTypes,使用Messages部分的消息定义来描述方法的签名(操作名称、输入参数和输出参数)。在PortTypes中具体说明时又包含两个元素:Bindings,指定PortTypes部分中每个操作的绑定信息。Services,指定每个绑定的Port地址。
抽象定义和具体说明,既是有一定的各自独立性,又有一定的相互关联性。还要说明的是在一个WSDL文档中可以没有Types部分,但如果有那么就只能有一个。
下面就来看看我们在前面的随笔中的Demo中所产生的WSDL文档,原文件如下:
1
<?xml version="1.0" encoding="utf-8"?>
2
<wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="http://tempuri.org/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="http://tempuri.org/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
3
<wsdl:types>
4
<s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/">
5
<s:element name="Login">
6
<s:complexType />
7
</s:element>
8
<s:element name="LoginResponse">
9
<s:complexType>
10
<s:sequence>
11
<s:element minOccurs="0" maxOccurs="1" name="LoginResult" type="s:string" />
12
</s:sequence>
13
</s:complexType>
14
</s:element>
15
<s:element name="MyServiceClassHeader" type="tns:MyServiceClassHeader" />
16
<s:complexType name="MyServiceClassHeader">
17
<s:sequence>
18
<s:element minOccurs="0" maxOccurs="1" name="UsN" type="s:string" />
19
<s:element minOccurs="0" maxOccurs="1" name="PaW" type="s:string" />
20
</s:sequence>
21
<s:anyAttribute />
22
</s:complexType>
23
<s:element name="SelectUser">
24
<s:complexType>
25
<s:sequence>
26
<s:element minOccurs="0" maxOccurs="1" name="UserName" type="s:string" />
27
</s:sequence>
28
</s:complexType>
29
</s:element>
30
<s:element name="SelectUserResponse">
31
<s:complexType>
32
<s:sequence>
33
<s:element minOccurs="0" maxOccurs="1" name="SelectUserResult">
34
<s:complexType>
35
<s:sequence>
36
<s:element ref="s:schema" />
37
<s:any />
38
</s:sequence>
39
</s:complexType>
40
</s:element>
41
</s:sequence>
42
</s:complexType>
43
</s:element>
44
</s:schema>
45
</wsdl:types>
46
<wsdl:message name="LoginSoapIn">
47
<wsdl:part name="parameters" element="tns:Login" />
48
</wsdl:message>
49
<wsdl:message name="LoginSoapOut">
50
<wsdl:part name="parameters" element="tns:LoginResponse" />
51
</wsdl:message>
52
<wsdl:message name="LoginMyServiceClassHeader">
53
<wsdl:part name="MyServiceClassHeader" element="tns:MyServiceClassHeader" />
54
</wsdl:message>
55
<wsdl:message name="SelectUserSoapIn">
56
<wsdl:part name="parameters" element="tns:SelectUser" />
57
</wsdl:message>
58
<wsdl:message name="SelectUserSoapOut">
59
<wsdl:part name="parameters" element="tns:SelectUserResponse" />
60
</wsdl:message>
61
<wsdl:portType name="MyServiceClassSoap">
62
<wsdl:operation name="Login">
63
<wsdl:input message="tns:LoginSoapIn" />
64
<wsdl:output message="tns:LoginSoapOut" />
65
</wsdl:operation>
66
<wsdl:operation name="SelectUser">
67
<wsdl:input message="tns:SelectUserSoapIn" />
68
<wsdl:output message="tns:SelectUserSoapOut" />
69
</wsdl:operation>
70
</wsdl:portType>
71
<wsdl:binding name="MyServiceClassSoap" type="tns:MyServiceClassSoap">
72
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
73
<wsdl:operation name="Login">
74
<soap:operation soapAction="http://tempuri.org/Login" style="document" />
75
<wsdl:input>
76
<soap:body use="literal" />
77
<soap:header message="tns:LoginMyServiceClassHeader" part="MyServiceClassHeader" use="literal" />
78
</wsdl:input>
79
<wsdl:output>
80
<soap:body use="literal" />
81
</wsdl:output>
82
</wsdl:operation>
83
<wsdl:operation name="SelectUser">
84
<soap:operation soapAction="http://tempuri.org/SelectUser" style="document" />
85
<wsdl:input>
86
<soap:body use="literal" />
87
</wsdl:input>
88
<wsdl:output>
89
<soap:body use="literal" />
90
</wsdl:output>
91
</wsdl:operation>
92
</wsdl:binding>
93
<wsdl:binding name="MyServiceClassSoap12" type="tns:MyServiceClassSoap">
94
<soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
95
<wsdl:operation name="Login">
96
<soap12:operation soapAction="http://tempuri.org/Login" style="document" />
97
<wsdl:input>
98
<soap12:body use="literal" />
99
<soap12:header message="tns:LoginMyServiceClassHeader" part="MyServiceClassHeader" use="literal" />
100
</wsdl:input>
101
<wsdl:output>
102
<soap12:body use="literal" />
103
</wsdl:output>
104
</wsdl:operation>
105
<wsdl:operation name="SelectUser">
106
<soap12:operation soapAction="http://tempuri.org/SelectUser" style="document" />
107
<wsdl:input>
108
<soap12:body use="literal" />
109
</wsdl:input>
110
<wsdl:output>
111
<soap12:body use="literal" />
112
</wsdl:output>
113
</wsdl:operation>
114
</wsdl:binding>
115
<wsdl:service name="MyServiceClass">
116
<wsdl:port name="MyServiceClassSoap" binding="tns:MyServiceClassSoap">
117
<soap:address location="http://localhost/WebServicesDemo/MyServiceClass.asmx" />
118
</wsdl:port>
119
<wsdl:port name="MyServiceClassSoap12" binding="tns:MyServiceClassSoap12">
120
<soap12:address location="http://localhost/WebServicesDemo/MyServiceClass.asmx" />
121
</wsdl:port>
122
</wsdl:service>
123
</wsdl:definitions>
从上面的WSDL文档中能非常容易的看见WSDL文档被分开为两个部分了,那就是在第45行和第46行。你能读懂这个WSDL文档吗?
2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

学会读WSDL文档有助于你在调用他人开发的Web Services时的理解和使用,WSDL文档就如同对Web Services使用的说明书,这就是我们为什么要讲解WSDL文档的一些内容的原因。