NODE-SOAP源码学习(一)

542 查看

背景

因为工作的关系,需要在node项目里调用webservice。服务端是java实现的。客户端使用node-soap。调用过程中,出现了server 500错误。node项目不能改,所以只好自己改node-soap源码。

SOAP机制总览

网上没有node-soap的源码解读可以参考,但是有gSoap;是一个C++实现的SOAP库。gSaop源码分析[1]
下面,我会列中核心的几个gSOAP的内容,看看node-soap中怎么对照实现的。

SOAP结构

SOAP结构

  • 必需的 Envelope 元素,可把此 XML 文档标识为一条 SOAP 消息,XML文件的顶层元素,代表该文件为SOAP消息

  • 可选的 Header 元素,包含头部信息

  • 必需的 Body 元素,包含所有的调用和响应信息

  • 可选的 Fault 元素,提供有关在处理此消息所发生错误的信息

  • 可选的Attachment,主要用于传递附件,扩展的SOAP消息

FAULT结构

  • <faultcode>供识别故障的代码

  • <faultstring>这里的错误是为人设定的,让人读懂,而不是为程序处理设定的。

  • <faultactor>有关是谁引发故障的信息

  • <detail>Body元素中的内容不能被成功地处理的时候,它就出现了。

SOAP命名空间

SOAP_NMAC struct Namespace namespaces[] =

{

{"SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/", "http://www.w3.org/*/soap-envelope", NULL},

{"SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/", "http://www.w3.org/*/soap-encoding", NULL},

{"xsi", "http://www.w3.org/2001/XMLSchema-instance", "http://www.w3.org/*/XMLSchema-instance", NULL},

{"xsd", "http://www.w3.org/2001/XMLSchema", "http://www.w3.org/*/XMLSchema", NULL},

{"ns", "urn:calc", NULL, NULL},

{NULL, NULL, NULL, NULL}

};

这里的URL并不是指向文件,而只是一个名字。如果一个SOAP应用程序接收了一个消息,而该消息的SOAP Envelope元素使用和上述不同的名称空间,则该应用程序就将其视为版本错误并忽略该消息。

gSOAP Keep-Alive和超时管理

gSOAP是绑定Http协议来对xml数据进行传输,一个SOAP请求实际上就是一个HTTP POST请求。消息从发送方到接受方方是单向传送,即以请求/应答的方式实现的。这也就是为什么生成的xml文件都是req,res成对出现的

XML介绍

Xml的全称是EXtensible Markup Language。可扩展标记语言。仅仅是一个纯文本。适合用于数据的存储和传输。里面的标签由作者赋予它含义
举例:

比如

<Email>

<From>a@domain.com/From>

<To>b@domain.com</To>

<Head>Hello</Head>

<Body>Hello World</Body>

</Email>

可以赋予这个xml文档含义是 a发送给b一封邮件,邮件标题是“Hello”,正文是“Hello World”

 <ns:add>

   <a>0.0</a>

   <b>0.0</b>

  </ns:add>

gSOAP赋予add为一个接口函数的名称,a和b是接口函数参数

XML命名空间

<?xml version="1.0" encoding="UTF-8"?>

<SOAP-ENV:Envelope

 xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

 xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"

 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

 xmlns:xsd="http://www.w3.org/2001/XMLSchema"

 xmlns:ns="urn:calc">

 <SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">

  <ns:add>

   <a>0.0</a>

   <b>0.0</b>

  </ns:add>

 </SOAP-ENV:Body>

</SOAP-ENV:Envelope>

命令空间的意义:

由于标签是我们自定义的,多个XML文件中可能存在重复命名,但表示的含义却不一样,为了解决XML文档中命名的冲突问题 就出现了命名空间。所以需要加上一个namespace来区分多个xml文件之间相同的标签。

使用语法:xmlns:namespace-prefix="namespaceURI"

xmlns:xsd="http://www.w3.org/2001/XMLSchema"

例如:xmlns:ns="urn:calc
其中calc是一个接口文件的文件名。这句是gsoap定义的默认命名空间;有了默认的命名空间
直接是<a>0.0</a>就可以,而不用<ns:a>0.0</ns:a>

命名空间的处理

关于命名空间的处理代码如下

SOAP_FMAC1 int SOAP_FMAC2 soap_match_namespace(struct soap*, const char *, const char*, size_t n1, size_t n2);

SOAP_FMAC1 int SOAP_FMAC2 soap_set_namespaces(struct soap*, const struct Namespace*);

SOAP_FMAC1 void SOAP_FMAC2 soap_set_local_namespaces(struct soap*);

SOAP_FMAC1 void SOAP_FMAC2 soap_pop_namespace(struct soap*);

SOAP_FMAC1 struct soap_nlist* SOAP_FMAC2 soap_push_namespace(struct soap*, const char *,const char *);

SOAP_FMAC1 const char* SOAP_FMAC2 soap_current_namespace(struct soap *soap, const char *tag);

SOAP_FMAC1 struct soap_nlist* SOAP_FMAC2 soap_lookup_ns(struct soap *soap, const char *tag, size_t n);

编码

XML Schema

定义了文档中的元素,属性,数据类型,默认值等.因为WSDL 是一种基于 schema 的语言,所以这个看WDSL文档更清楚

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="HelloWorld">
6 <s:complexType>
7 <s:sequence>
8 <s:element minOccurs="1" maxOccurs="1" name="i" type="s:int" />
9 </s:sequence>
10 </s:complexType>
11 </s:element>
12 <s:element name="HelloWorldResponse">
13 <s:complexType>
14 <s:sequence>
15 <s:element minOccurs="1" maxOccurs="1" name="HelloWorldResult" type="s:dateTime" />
16 </s:sequence>
17 </s:complexType>
18 </s:element>
19 </s:schema>
20 </wsdl:types>
21 <wsdl:message name="HelloWorldSoapIn">
22 <wsdl:part name="parameters" element="tns:HelloWorld" />
23 </wsdl:message>
24 <wsdl:message name="HelloWorldSoapOut">
25 <wsdl:part name="parameters" element="tns:HelloWorldResponse" />
26 </wsdl:message>
27 <wsdl:portType name="ServiceSoap">
28 <wsdl:operation name="HelloWorld">
29 <wsdl:input message="tns:HelloWorldSoapIn" />
30 <wsdl:output message="tns:HelloWorldSoapOut" />
31 </wsdl:operation>
32 </wsdl:portType>
33 <wsdl:binding name="ServiceSoap" type="tns:ServiceSoap">
34 <soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
35 <wsdl:operation name="HelloWorld">
36 <soap:operation soapAction="http://tempuri.org/HelloWorld" style="document" />
37 <wsdl:input>
38 <soap:body use="literal" />
39 </wsdl:input>
40 <wsdl:output>
41 <soap:body use="literal" />
42 </wsdl:output>
43 </wsdl:operation>
44 </wsdl:binding>
45 <wsdl:binding name="ServiceSoap12" type="tns:ServiceSoap">
46 <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" />
47 <wsdl:operation name="HelloWorld">
48 <soap12:operation soapAction="http://tempuri.org/HelloWorld" style="document" />
49 <wsdl:input>
50 <soap12:body use="literal" />
51 </wsdl:input>
52 <wsdl:output>
53 <soap12:body use="literal" />
54 </wsdl:output>
55 </wsdl:operation>
56 </wsdl:binding>
57 <wsdl:service name="Service">
58 <wsdl:port name="ServiceSoap" binding="tns:ServiceSoap">
59 <soap:address location="http://localhost:2206/WebSite1/Service.asmx" />
60 </wsdl:port>
61 <wsdl:port name="ServiceSoap12" binding="tns:ServiceSoap12">
62 <soap12:address location="http://localhost:2206/WebSite1/Service.asmx" />
63 </wsdl:port>
64 </wsdl:service>
65 </wsdl:definitions>

一个WSDL文档由四部分组成:

  • types
      指定了WebService用到的所有数据类型,上面用到了两种数据类型,int和datetime

  • message
    指明一个操作所用到的数据类型。

    • HelloWorldSoapIn是指HelloWorld的输入操作用到的数据类型,HelloWorldSoapOut是

    • HelloWorld的输出操作用到的数据类型。二者的element元素指出了与types中对应到的具体类型。

  • portType

    • 指出了这个WebService所有支持的操作,就是说有哪些方法可供调用。

    • 这里支持一个HelloWorld调用,它的输入和输出对应到HelloWorldSoapIn和HelloWorldSoapOut这个两个数据类型。

  • binding

    • soap12:binding元素的transport指明传输协议,这里是http协议。

    • operation 指明要暴露给外界调用的操作。

    • use属性指定输入输出的编码方式,这里没有指定编码。

  • services
      指定服务的一些信息,主要是指定服务的访问路径。