WebService服務提供的介面,soap協議的報文中,引數必須符合順序
問題的由來
專案的一個介面,是通過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
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.