最近在工作中遇到一個SOAP Action的問題,正好拿出來研究一把。
據說SOAPAction header這玩意在SOAP 1.1規範中著實讓不少開發人員喝了一壺。真的有這麼難理解嗎?我想這應該是因為SOAP有兩種非常不同的使用方式,而SOAPAction主要是被用來支援其中應用較少的一種方式的原因。在我看來,這種方式也非常有價值。
讓我們先看看SOAP 1.1規範是怎麼定義HTTP SOAPAction header的:
SOAPAction HTTP request header被用來標識SOAP HTTP請求的目的地,其值是個URI地址。SOAP發送並不限制格式、URI特徵或其必須可解析,那麼在這種情況下,發送一個HTTP SOAP請求時,其HTTP用戶端必須使用/指明SOAPAction HTTP request header。
SOAPAction header的內容可以被用在服務端,諸如:防火牆適當的過濾基於HTTP的SOAP請求訊息等情境。SOAPAction header的值為空白串("")表示SOAP訊息的目的地由HTTP請求的URI標識;無值則表示沒有指定這條訊息的目的地。
看了官方的定義,相信大家也迷糊了,迷糊在“目的地”這個詞上吧?那麼,給它一個準確的說法吧——“確定執行某一行為的路徑”。
看一個SOAP訊息的例子:
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<m:GetLastTradePrice xmlns:m="Some-URI">
<symbol>XYS</symbol>
</m:GetLastTradePrice>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
很明顯的,這條訊息指明了要去執行服務端的“GetLastTradePrice”這個方法,開發人員不會對此沒有疑問,這樣看來,SOAP Action也許顯得多餘了?
然而,在另一種SOAP訊息的發送情境中,卻少不了SOAP Action。在這種情境中,SOAP訊息並沒有顯示的指定要調用的服務方法名,而是利用底層的傳輸協議發送(這樣的話,一般會被Web services忽視),例如使用HTTP的Post方式發送的SOAP訊息。
拿AWT組件容器來舉個例子吧,我們知道有很多AWT容器,例如:Panel,Box,Window等等,很多情況下,開發人員知道他們建立的泛型容器物件下真正是什麼對象。那麼,假設下面兩段代碼裡的java.awt.Container對象其實是一個Box吧:
1.
comp = new TextField( "test" );
java.awt.Container c = Foo.bar();
c.add( comp );
2.
comp = new TextField( "test" );
java.awt.Container c = Foo.bar();((java.awt.Panel)c).add( comp );
以上兩段代碼產生兩種不同的結果。“add()”方法對兩者似乎有著相同的意義,但是在代碼2中其被擴充為“作為一個Panel對象去add”。所以很明顯的,代碼2會拋出一個異常,因為我們知道這個對象實際上是Box,而我們的代碼期待的是Panel。
HTTP POST的意義正如這個例子中的“add()”方法一樣,HTTP POST提供一個關於SOAPAction如何被使用的索引;而SOAPAction header的值則應該被用來指明這個“擴充”的目的地——這條SOAP/HTTP訊息寄件者所期待的處理容器的名稱(可以這樣理解:即相應的API方法)。那麼,正如上面那個AWT例子一樣,如果這種期待沒有被滿足,就會產生一個錯誤。
注意:在SOAP 1.2規範中,SOAPAction header這個屬性被"action"所取代,但其作用和工作原理都沒有變化。
有意思的是,在Tibco的EAI工具BW中,使用SOAP服務端活動必須指定SOAP Action屬性,如果引用的原始WSDL沒有使用這個屬性的話,也必須顯示的指明;因此,相應的,其用戶端也要注意啦——必須為SOAP Action屬性填入期待的URI。OK