1. 程式人生 > 其它 >WebService服務提供的介面,soap協議的報文中,引數必須符合順序

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