WebService服务提供的接口,soap协议的报文中,参数必须符合顺序
「掠影浮光」XML Schema,xsd:sequence specifies child elements can only appear in the order mentioned.
问题的由来
项目的一个接口,是通过dubbo提供的配置,暴露出的一个webservice接口,可以看相关文档,其实也是委托给了cxf这个开源组件来做的。
因为提供给了其他厂商调用,结果他们调用后一直失败,接口进来了,打印的两行都为空。
把报文要了过来,重新配置了命名空间,还有调整两个参数的顺序(他们原来是反的),就正常了。
对方的工作人员说,这两个参数的顺序为什么一定要按照顺序,我也只是说不按照顺序就会有问题。但还是好奇,就打断点进去看了下cxf是怎么处理的。
cxf对soap协议解析参数的源码
可以看出,dubbo的ws服务协议也是委托给了cxf下的ServletController处理;项目中用到的cxf是cxf-api.2.6.1.jar,是在org.apache.cxf.interceptor.DocLiteralInInterceptor.getPara(DepthXMLStreamReader, DataReader, MessageContentsList, Iterator, Message),这个方法处理了(我再在cxf的官网的api中DocLiteralInInterceptor没有getPara这个方法,2.6,2.4,3.1各个版本都没看到)
private void getPara(DepthXMLStreamReader xmlReader,
DataReader<xmlstreamreader> dr,
MessageContentsList parameters,
Iterator<messagepartinfo> itr,
Message message) {
boolean hasNext = true;
while (itr.hasNext()) {
MessagePartInfo part = itr.next();
if (hasNext) {
hasNext = StaxUtils.toNextElement(xmlReader);
}
Object obj = null;
if (hasNext) {
QName rname = xmlReader.getName();
while (part != null
&& !rname.equals(part.getConcreteName())) {
if (part.getXmlSchema() instanceof XmlSchemaElement) {
//TODO - should check minOccurs=0 and throw validation exception
//thing if the part needs to be here
parameters.put(part, null);
}
if (itr.hasNext()) {
part = itr.next();
} else {
part = null;
}
}
if (part == null) {
return;
}
if (rname.equals(part.getConcreteName())) {
obj = dr.read(part, xmlReader);
}
}
parameters.put(part, obj);
}
}
在这里,MessagePartInfo应该是从wsdl中解析出来的,就是定义好的参数,Qname rname是真实传过来的xml中读取出来的,这个时候,part指向的是arg0,但是while第一次循环的时候,rname传过来的参数中的第一个值(因为顺序是反的,为arg1),rname不等于part.getConcreateName(),就直接把parameter.put(part, null)了;接着往下走,part取了arg1,这个时候rname也指向arg1,就把arg1的值read过来为obj,再放入parameter中;itr的两个元素已经循环完了,跳出while循环,真实过来过来的soap协议中的arg0的参数就被跳过去了。
<soapenv:envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.xxx">
<soapenv:header>
<soapenv:header>
<soapenv:body>
<ser:syncunitework>
<ser:arg1>arg1</ser:arg1>
<ser:arg0>arg0</ser:arg0>
</ser:syncunitework>
</soapenv:body>
</soapenv:header></soapenv:header></soapenv:envelope>
附上wsdl文件的关于接口入参的部分
<xsd:element name="sync" type="tns:sync">
<xsd:complextype name="sync">
<xsd:sequence>
<xsd:element minoccurs="0" name="arg0" type="xsd:string">
<xsd:element minoccurs="0" name="arg1" type="xsd:string">
</xsd:element></xsd:element></xsd:sequence>
</xsd:complextype>
顺序的规范
cxf 下面截取一下官方文档的描述 http://cxf.apache.org/docs/overview.html
Apache CXF™ is an open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS and JAX-RS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI.
XML Schema https://www.w3schools.com/xml/schema_intro.asp
An XML Schema describes the structure of an XML document.
The XML Schema language is also referred to as XML Schema Definition (XSD).
XML Schema sequence Element https://www.w3schools.com/xml/el_sequence.asp
The sequence element specifies that the child elements must appear in a sequence. Each child element can occur from 0 to any number of times.
XML WSDL https://www.w3schools.com/xml/xml_wsdl.asp
- WSDL stands for Web Services Description Language
- WSDL is used to describe web services
- WSDL is written in XML
- WSDL is a W3C recommendation from 26. June 2007
总结
wsdl是webservice的描述,也是用到了xsd来约束,其中参数(即sync方法)的两个参数就是有顺序的,所以归根到底,是xsd的规范的约束。这一点也从问答网站stackoverflow的提问得到了印证。
<xsd:all>
specifies that the child elements can appear in any order.
<xsd:sequence>
specifies child elements can only appear in the order mentioned.