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.

https://stackoverflow.com/questions/16101488/difference-between-xsdall-and-xsdsequence-in-schema-definition

版权声明:本文为Jimmy-cnblog原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/Jimmy-cnblog/p/15235380.html