早先的一些blog文章已经说了很多关于Web Service客户端在同一种语言实现或者不同语言实现中由于细节实现不同导致兼容性的问题。昨天解决的问题在一个边界问题上又一次说明了这种异构环境的互通标准在不同的实现当中,由于细节理解不同会造成一些兼容性问题。
问题:
当接口返回类型为一个对象,同时这个对象中有一个属性是数组类型,那么这个数组类型的对象在返回的SOAP消息中就无法正确解析。如下定义了一个对象:
publicclass DemoStruct implements Serializable
{
private RecordType[] recordArr;
private String name;
public RecordType[] getRecordArr(){returnrecordArr;}
publicvoid setRecordArr(RecordType[] recordArr){this.recordArr = recordArr;}
public String getName(){returnname;}
publicvoid setName(String name){this.name = name;}
}
接口定义如下:
publicinterface IDemoTest
{
DemoStruct queryAccountRecord(String account);
}
问题分析:
在早先返回数组对象的问题上已经解决了,但是当数组归属于对象,作为一个属性的时候,出现了问题。
首先在wsdl中定义一个类型是数组有两种方式:
1. 定义maxoccurs=”unbounded”。
<xsd:complexType name="ArrayOfRecordType">
<xsd:sequence>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="RecordType" nillable="true" type="ns1:RecordType"/>
</xsd:sequence>
</xsd:complexType>
2. 定义soap encoding中的arrayType类型。
<xs:complexType name="ArrayOfRecordType">
<xs:complexContent>
<xs:restriction base="soapenc:Array">
<xs:attribute ref="soapenc:arrayType" wsdl:arrayType="ax22:RecordType[]"></xs:attribute>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
如果对于Java客户端和服务端来说,这两种配置方式没有什么太大区别,但是如果对于.net来说,后者较好,可以产生ArrayOfRecordType的数组片断类型,手动解析数组内部信息。
首先ASF中集成的是Axis2的服务框架,因此出现这类问题要确定是集成中的定制导致SOAP消息出现了问题还是Axis2服务端本身解析的时候就有问题。搭建了基于Tomcat的axis2和xfire两个发布环境和ASF的服务发布环境,同时用SoapUI工具来截取消息返回包,根据返回的情况可以确认Axis2和ASF两者返回的SOAP消息一致,Xfire返回的消息为另外一种形式。
Xfire返回的SOAP消息包:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<queryAccountRecordResponse xmlns="http://cmptest2.webservice.asf.xplatform.alisoft.com">
<out>
<name xmlns="http://cmptest.webservice.asf.xplatform.alisoft.com">1</name>
<recordArr xmlns="http://cmptest.webservice.asf.xplatform.alisoft.com">
<RecordType>
<accountBalance>12.12</accountBalance>
<accountId>1</accountId>
<isDeleted>false</isDeleted>
</RecordType>
<RecordType>
<accountBalance>12.12</accountBalance>
<accountId>1</accountId>
<isDeleted>false</isDeleted>
</RecordType>
</recordArr>
</out>
</queryAccountRecordResponse>
</soap:Body>
</soap:Envelope>
Axis2和ASF返回的消息包:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:queryAccountRecordResponse xmlns:ns="http://cmptest.webservice.asf.xplatform.alisoft.com">
<ns:return type="com.alisoft.xplatform.asf.webservice.cmptest.DemoStruct" xmlns:ax21="http://cmptest.webservice.asf.xplatform.alisoft.com/xsd">
<ax21:name>1</ax21:name>
<ax21:recordArr type="com.alisoft.xplatform.asf.webservice.cmptest.RecordType">
<ax21:accountBalance>12.12</ax21:accountBalance>
<ax21:accountId>1</ax21:accountId>
<ax21:isDeleted>false</ax21:isDeleted>
</ax21:recordArr>
<ax21:recordArr type="com.alisoft.xplatform.asf.webservice.cmptest.RecordType">
<ax21:accountBalance>12.12</ax21:accountBalance>
<ax21:accountId>1</ax21:accountId>
<ax21:isDeleted>false</ax21:isDeleted>
</ax21:recordArr>
</ns:return>
</ns:queryAccountRecordResponse>
</soapenv:Body>
</soapenv:Envelope>
根据报文可以很明显的看出,Axis2是将数组属性对象拆分为多个片断,并行放在SOAP中,每个片段的标签就是这个数组属性的名称。Xfire是将数组属性作为一个单独的片断,然后片断中包含了多个实体片断,片段的标签是实体对象名称。考虑一下wsdl中定义的情况,自己觉得Xfire是比较合理的解析方式,加上同时早期对于java 开发的ISV提倡使用xfire客户端,因此打算改造集成在ASF中Axis2的服务端和客户端。
问题的解决方案:
其实Axis2在做SOAP输出的时候主要经历了这么几部分,将返回的对象转变成为dom tree,然后将dom tree转换成为xml stream,最后转换成为soap消息包。因此只需要将对象转变成为dom tree时结构修正,那么就可以保证后续的工作正常。同样ASF客户端就是一个反向过程,只需要将dom tree转换成为对象改造一下就可以了。细节不做赘述。
问题的反复:
改造以后ASF框架已经能够返回Xfire可识别的消息结果,XFire问题解决。但是因为修改了比较多的内容,因此需要做全面的单元测试,结果一测试果然发现了问题,发现原来正常的接口返回数组对象情况不能正常。
截获SOAP消息以后发现如果返回数组类型原来的SOAP消息包如下:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<getUserAccountArrResponse xmlns="http://webservice.asf.xplatform.alisoft.com">
<out>
<ns1:AccountBean xmlns:ns1="http://object.webservice.asf.xplatform.alisoft.com">
<accountBalance xmlns="http://object.webservice.asf.xplatform.alisoft.com">100.23</accountBalance>
<accountId xmlns="http://object.webservice.asf.xplatform.alisoft.com">1</accountId>
<isDeleted xmlns="http://object.webservice.asf.xplatform.alisoft.com">false</isDeleted>
</ns1:AccountBean>
<ns1:AccountBean xmlns:ns1="http://object.webservice.asf.xplatform.alisoft.com">
<accountBalance xmlns="http://object.webservice.asf.xplatform.alisoft.com">111.23</accountBalance>
<accountId xmlns="http://object.webservice.asf.xplatform.alisoft.com">11</accountId>
<isDeleted xmlns="http://object.webservice.asf.xplatform.alisoft.com">false</isDeleted>
</ns1:AccountBean>
</out>
</getUserAccountArrResponse>
</soap:Body> </soap:Envelope>
现在却在out后面多了一层ArrayOfAccountBean的标签,其实这就是刚才修改所造成的,而Xfire和axis2都不能够解析此类返回。
考虑了一下原因,其实如果数组作为结果返回的时候是不需要再多封装一层,而作为其他对象的属性的时候由于要复制给对象,因此需要将属性名称作为外围标签。所以还需要再次修改服务端,需要在数组封装返回的时候做判断,如果返回的数组是作为数组结果返回,那么不需要再次封装,如果是作为对象属性来返回,那么需要再次封装。
调整服务端以后作了全面的单元测试,一切正常。
后语:
现在由于SOA盛行,而Web Service作为SOA的技术解决手段被越来越广泛的使用,虽然SOAP消息和wsdl的标准都是规范性的定义,但是涉及到了细节实现,不同的框架开发者和不同语言的开发设计者都有不同的理解,稍有不同的理解偏差,就会导致同一种协议的不同客户端和服务端无法相互兼容,这类问题在通信行业中很常见,不同的终端手机的兼容性往往是增值业务开发者最头痛的问题。细节决定成败,跨平台的路还很长。
分享到:
相关推荐
.NET Framework为创建和消费Web Service提供了丰富的支持,而.NET Web Service Studio则是一个专门针对这一框架的调试工具,它极大地简化了Web Service的开发过程。 .NET Web Service Studio的核心功能包括: 1. *...
ASP.NET Web Service是微软.NET Framework框架中用于构建网络服务的重要技术。它允许开发人员创建能够通过互联网进行通信的可互操作的应用程序。Web服务是一种基于XML(eXtensible Markup Language)的标准化方法,...
在探讨WCF(Windows Communication Foundation)、.NET Remoting和Web Service之间的概念及其差异之前,我们先简要回顾一下这三种技术的历史背景和发展脉络。 #### 1\. WCF:统一的通信框架 WCF作为微软.NET ...
Web Service是一种基于互联网的、平台无关的应用程序接口,它通过标准的XML(如SOAP)进行通信,允许不同系统之间的数据交换。在这个场景下,我们可以找到一个提供代码转换服务的Web Service,该服务可以接收C#代码...
本文将深入探讨两种常见的Web服务实现方式:Windows Communication Foundation (WCF) 和 Web Service(通常指的是ASMX或SOAP Web服务)。我们将通过一个名为"WCFDemo"的压缩包文件中的例子来阐述它们的核心概念、...
1. **Web服务支持**:CXF支持多种Web服务标准,如SOAP、RESTful API、WS-*(包括WS-Security、WS-ReliableMessaging等)、JAX-RS(Java API for RESTful Web Services)和JAX-WS(Java API for XML Web Services)。...
接着,使用工具(如`wsimport`或Apache CXF的`wsdl2java`)从Java接口生成WSDL(Web Service Description Language)文件,这是描述WebService的规范。 2. **C#客户端调用**: 在C#中,我们可以利用.NET Framework...
Web Service基于SOAP协议,遵循WS-I标准,因此具有跨平台和互操作性的优势,但需要IIS等应用服务器进行托管,直到.NET Framework 3.0引入ServiceHost才有所改善。而.NET Remoting则更加灵活,可以独立于IIS运行,也...
【Web服务(Web Service)与C#】 Web服务是一种基于互联网的、使用标准XML(Extensible Markup Language)进行通信的应用程序。它允许不同系统之间的数据交换,无视平台或编程语言的差异。C#,作为微软.NET框架的...
`getPortClassMap` 方法名看起来与网络服务或者Web服务客户端相关,可能是在处理SOAP(Simple Object Access Protocol)或者是RESTful API时的一个接口或服务端点。在Java Web服务客户端编程中,这类方法通常用于...
OGSI(Open Grid Service Infrastructure)和WSRFC(Web Services Resource Framework)是为了解决Grid和Web服务之间的差异而提出的,它们关注资源识别、元数据管理、生命周期管理以及状态监控等关键领域。...
- **消息封装**: SOAP(Simple Object Access Protocol)是一种基于XML的消息交换协议,用于封装Web Service的请求和响应,确保了数据的安全传输和正确解析。 - **服务描述**: WSDL(Web Services Description ...
5. Web Service是一种基于XML的通信方式,通过SOAP(简单对象访问协议)进行消息交换,使用WSDL(Web服务描述语言)描述服务接口,并通过UDDI(统一描述、发现与集成)进行服务发现。Web服务使得不同系统间的数据...
3. **实现服务端**:解释如何将接口实现为具体的服务,包括服务类的编写、WSDL(Web Service Description Language)的生成以及部署到应用服务器。 4. **创建客户端**:说明如何使用CXF的客户端API调用远程服务,...
.NET Framework作为核心,包含公共语言运行库和基类库,消除了不同编程语言之间的差异,提供了全面的面向对象功能。.NET Remoting技术则允许不同应用程序域间的对象通信,提供了多种激活模式,如Singleton Remoting...
JavaScript调用WebService是一种常见的在客户端与服务器之间进行数据交互的方式,尤其在Web应用程序中,它允许JavaScript代码直接访问Web服务提供的功能。以下是对这个实例的详细解析和相关知识点的总结: 1. ...