一、概述
SOAP原意為Simple Object Access Protocol(簡單對象訪問協議),是一個用于分布式環境的、輕量級的、基于XML進行信息交換的通信協議(SOAP is an XML based protocol used to exchange information throughout a distributed environment)。
以下是w3c網站上的定義:
SOAP Version 1.2 (SOAP) is a lightweight protocol intended for exchanging structured information in a decentralized, distributed environment. It uses XML technologies to define an extensible messaging framework providing a message construct that can be exchanged over a variety of underlying protocols. The framework has been designed to be independent of any particular programming model and other implementation specific semantics.
可以認為SOAP是XML-RPC的高級版本,二者基于相同的原理:利用HTTP + XML封裝進行RPC調用。
SOAP最初由MS發起研究,用以解決MTS/COM資源消耗大,不夠輕巧等問題,后逐漸被IBM等巨頭接納并加入研究,現已提交W3C,成為Web Service應用傳輸標準。對于輕量級、可擴展Web Service應用協議的需求促成了SOAP的廣泛應用,也間接促進了XML的流行。關于相關歷史的更多信息,見http://www.microsoft.com/china/MSDN/library/WebServices/WebServices/SOAPSpecificationIndexPage.mspx或http://www-128.ibm.com/developerworks/cn/webservices/ws-ref1/index.html。
二、SOAP數據包結構解析
SOAP的消息被稱為一個SOAP Envelope,包括SOAP Header和SOAP Body。其中,SOAP Header可以方便的插入各種其它消息來擴充Web Service的功能,比如Security(采用證書訪問Web Service),SOAP Body則是具體的消息正文,也就是Marshall后的信息。
SOAP調用的時候,也就是向一個URL(比如http://api.google.com/search/beta2)發送HTTP Post報文(根據SOAP規范,HTTP Get報文也可被支持),調用方法的名字在HTTP Request Header SOAP-Action中給出,接下來就是SOAP Envelope了。服務端接到請求,執行計算,將返回結果Marshall成XML,用HTTP返回給客戶端。
以下是一個典型的SOAP數據包:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<m:transaction xmlns:m="soap-transaction" s:mustUnderstand="true">
<transactionID>1234</transactionID>
</m:transaction>
</s:Header>
<s:Body>
<n:purchaseOrder xmlns:n="urn:OrderService">
<from>
<person>Christopher Robin</person>
<dept>Accounting</dept>
</from>
<to>
<person>Pooh Bear</person>
<dept>Honey</dept>
</to>
<order>
<quantity>1</quantity>
<item>Pooh Stick</item>
</order>
</n:purchaseOrder>
</s:Body>
</s:Envelope>
其中包含了一些SOAP規范定義的標簽,同時也可以包含一些具體應用相關的標簽。
Note:
如果你是一個普通的應用開發者,以上介紹已經足夠了,因為相應的SOAP應用平臺會負責完成相應SOAP數據包的打包和解析;如果你是一個SOAP應用平臺的實現者,關于SOAP基礎理論的更多介紹可參考《Programming Web Services with SOAP》一書或SOAP Specification(http://www.w3.org/TR/soap12-part0/)。
三、安裝Apache Axis
Apache Axis本身也是一個Web Project,它內建了對SOAP的編碼、解析,并為Client提供了一些使用SOAP Service的API,同時,為Web Service的發布提供管理,并對Client提交的處理請求作出響應。對于基于Axis的應用而言,我們可以將注意力完全放在具體Service和Client的設計上,而無需考慮中間的傳輸過程(對于Client而言,還需要使用一些Axis提供的訪問SOAP服務的特定API),這一點是與XML RPC不同的地方。
Apache Axis可以從http://ws.apache.org/axis/下載,當前的最新版本是1.4。
安裝Axis的過程很簡單:
1、解壓Axis到任意目錄下;
2、拷貝Axis目錄下的webapps/axis目錄到%TOMCAT_HOME%/webapps下;
3、為了便于編譯和測試程序,添加環境變量:
AXIS_HOME Axis的解壓目錄
AXIS_LIB %AXIS_HOME%/lib
AXISCLASSPATH %AXIS_LIB%/axis.jar;%AXIS_LIB%/commons-discovery-0.2.jar;%AXIS_LIB%/commons-logging-1.0.4.jar;%AXIS_LIB%/jaxrpc.jar;%AXIS_LIB%/saaj.jar;%AXIS_LIB%/log4j-1.2.8.jar
完成上述工作后,啟動Tomcat,并用IE打開:http://localhost:8080/axis/,點擊其中的Validation、List兩個鏈接,如果沒有報告任何錯誤,則說明Axis安裝成功。
關于Apache Axis安裝的更多信息可以參考官方文檔:http://ws.apache.org/axis/java/install.pdf。
四、舉例
有了上面對SOAP的基本理解,下面我們體驗一下Apache Axis 1.4提供的SOAP服務。
以下面EchoService為例:
public class EchoService {
public String echoString(String name) {
return name;
}
}
其對應的Client程序如下所示:
package demo.soap;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.namespace.QName;
public class EchoClient {
public static void main(String [] args) {
try {
String endpoint = "http://localhost:8080/axis/EchoService.jws";
// Create Service and Call object to set up a SOAP RPC
Service service = new Service();
Call call = (Call)service.createCall();
// Tells which service and method will be invoked
call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setOperationName(new QName("echoString"));
// Invoke method with required parameters
String ret = (String)call.invoke(new Object[] { "Hello!" });
System.out.println("Sent 'Hello!', got '" + ret + "'");
} catch (Exception e) {
System.err.println(e.toString());
}
}
}
對于Client程序而言,對Axis Service進行訪問的基本方法是:
1、創建Service及Call對象;
2、設置Call對象屬性,如訪問點(標明將訪問哪個Axis Service)及方法名等;
3、傳入參數數組,調用Call對象的invoke方法。
可使用如下命令編譯EchoClient.java:
javac -cp %AXISCLASSPATH% EchoClient.java
在Axis中,存在兩種發布SOAP Service的方法。
方法一:
將源程序EchoService.java拷貝到%TOMCAT_HOME%/webapps/axis下,并將其后綴改為.jws即可。
第一種方法非常的簡單,但是第一種發布方法存在幾個重要的限制:
1、不能指定package;
2、需要有Service的源碼;
因此常常不能滿足我們的需要。
方法二:
第二種發布Axis Service的方法需通過配置來完成。
以下面的HelloService為例(與前面的EchoService基本沒有什么區別,但其中使用了package):
package demo.soap;
public class HelloService {
public String sayHello() {
return "Hello World!";
}
}
要發布上面的Service,需編寫如下的配置文件:
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="HelloService" provider="java:RPC">
<parameter name="className" value="demo.soap.HelloService"/>
<parameter name="allowedMethods" value="*"/>
</service>
</deployment>
將上述內容保存為%TOMCAT_HOME%/webapps/axis/WEB-INF/deploy.txt,并在其所在目錄下執行:
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.txt
生成server-config.wsdd文件,打開該文件看一下,可以看到HelloService的相關信息已被添加到該文件,此外,還包括一些默認的配置信息以及AdminService、Version兩個基礎服務。
以下是HelloService的Client程序的相關代碼:
package demo.soap;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
public class HelloClient {
public static void main(String [] args) throws Exception {
String endpoint = "http://localhost:" + "8080" + "/axis/services/HelloService"; // Attention: A little difference
Service service = new Service();
Call call = (Call)service.createCall();
call.setTargetEndpointAddress(new java.net.URL(endpoint));
call.setOperationName("sayHello");
String res = (String)call.invoke(new Object[] {});
System.out.println(res);
}
}
與前面的EchoClient的區別僅在于訪問點稍有不同。
發布后如何刪除對應的Service呢?要刪除上面發布的HelloService服務,只需在%TOMCAT_HOME%/webapps/axis/WEB-INF目錄下添加如下的undeploy.txt描述文件,其內容如下:
<undeployment xmlns="http://xml.apache.org/axis/wsdd/">
<service name="HelloService"/>
</undeployment>
然后執行:
java -cp %AXISCLASSPATH% org.apache.axis.client.AdminClient deploy.txt
以更新server-config.wsdd文件。
刷新一下頁面:
http://localhost:8080/axis/servlet/AxisServlet
將看到前面已發布的對應的Service已被刪除。
如果以后還要發布新的Service,你可以選擇直接更新上面產生的server-config.wsdd文件,或者重復上面的步驟。
Note:除了發布自己的Web Service到Axis,你也可以將Axis集成到自己的Web Application,具體方法見http://ws.apache.org/axis/java/install.pdf。
五、Google Web API
在繼續下面的討論之前,先娛樂一下,談談Google Web API。
為了便于程序員體驗Google的搜索服務,或者將Google的搜索服務集成到自己的應用中,Google于2002發布了Google Web API,可以讓世界各地的Java、.NET、Perl、Python等程序員,免費地通過Google提供的SOAP開發接口以Web Services的方式,對Google下達查找指令,并且可以將結果使用于自己的程序或網頁中。(不過使用上也有限制,它一天只允許未付費的程序員查找1000次。要使用前,必須先向Google注冊帳號,取得一個32位長度的license key,每次呼叫查詢時,必須帶入這個license key。)
通過使用Google Web API,能夠從Google那兒以結構化數據的形式(xml格式)取得檢索結果,所帶來的最大好處就是你可以根據你自己的意愿和設計,把這些檢索結果顯示你自己的頁面上。這個頁面上可顯示自己的logo或一些其它的內容,就象自己編寫的頁面一樣,而不必非要把Google的logo顯示在頁面的頂部和底部。一句話,你可以控制Google的檢索了,讓Google為你的網站服務。(參考5)
以下是使用Proxy連接Google SOAP服務的例子:
java -cp googleapi.jar -Dhttp.proxyHost=xxx(proxy_host_ip/name) -Dhttp.proxyPort=xxx(proxy_port) com.google.soap.search.GoogleAPIDemo xxx(license_key) search billdavid
其輸出大致如下:
Parameters:
Client key = o917zHlQFHIr2+qMGPUYflB+j89LLbcX
Directive = search
Args = billdavid
Google Search Results:
======================
{
TM = 0.694308
Q = "billdavid"
CT = ""
TT = ""
CATs =
{
<EMPTY>
}
Start Index = 1
End Index = 10
Estimated Total Results Number = 1280
Document Filtering = true
Estimate Correct = false
Rs =
{
[
URL = "http://forums.vandyke.com/member.php?u=2050"
Title = "VanDyke Software Forums - View Profile: <b>billdavid</b>"
Snippet = "This is a discussion forum for users and evaluators of VanDyke Soft
ware products."
Directory Category = {SE="", FVN=""}
Directory Title = ""
Summary = ""
Cached Size = "16k"
Related information present = true
Host Name = ""
],
[
URL = "http://forums.vandyke.com/showthread.php?t=1393"
Title = "Will you add two new features to SecureCRT? - VanDyke Software Forums
"
Snippet = "<b>billdavid billdavid</b> is offline. Registered User. Join Date:
Apr 2006 <b>...</b><br> Originally Posted by <b>billdavid</b>. I think the foll
owing features are very useful: <b>...</b>"
Directory Category = {SE="", FVN=""}
Directory Title = ""
Summary = ""
Cached Size = "30k"
Related information present = true
Host Name = "forums.vandyke.com"
],
[
URL = "http://www.beliefnet.com/user/profile_view.asp?userID=424089&popUp=1"
Title = "Beliefnet Member Profile"
Snippet = "Member Name: <b>billdavid</b>. Member since: 2/24/2003. Location: s
ebring, florida , us.<br> Sex: Male. Age: 53. Occupation: Other. Organizations
and Affiliations: <b>...</b>"
Directory Category = {SE="", FVN=""}
Directory Title = ""
Summary = ""
Cached Size = "8k"
Related information present = true
Host Name = ""
],
(下略...)
以下是通過ethereal抓到的本機發出的Google Search數據包:
POST http://api.google.com/search/beta2 HTTP/1.0
Host: api.google.com
Content-Type: text/xml; charset=utf-8
Content-Length: 864
SOAPAction: "urn:GoogleSearchAction"
<?xml version='1.0' encoding='UTF-8'?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance" xmlns:xsd="http://www.w3.org/1999/XMLSchema">
<SOAP-ENV:Body>
<ns1:doGoogleSearch xmlns:ns1="urn:GoogleSearch" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<key xsi:type="xsd:string">xxx…xxx</key>
<q xsi:type="xsd:string">billdavid</q>
<start xsi:type="xsd:int">0</start>
<maxResults xsi:type="xsd:int">10</maxResults>
<filter xsi:type="xsd:boolean">true</filter>
<restrict xsi:type="xsd:string"></restrict>
<safeSearch xsi:type="xsd:boolean">false</safeSearch>
<lr xsi:type="xsd:string"></lr>
<ie xsi:type="xsd:string">UTF-8</ie>
<oe xsi:type="xsd:string">UTF-8</oe>
</ns1:doGoogleSearch>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
com.google.soap.search.GoogleAPIDemo.java的源代碼可以在googleapi的壓縮包中找到,其中演示了大部分基本Google Web API的用法,關于Google Web API的更多信息見參考4。
六、Axis2
隨著Web Services技術的演進,Apache Web Services中間件也在不斷發展,從第一代的Apache SOAP,第二代的Axis,逐漸發展成為第三代Web Service中間件Axis2。與Axis相比,Axis2采用了性能更為優越的XML解析技術,采用面向組件的架構設計,從而具有更好的靈活性和可擴展性,并可支持異步通信需求等。參考6、7給出了利用Axis2進行Web Service開發的詳細步驟。
參考:
1. 勞虎,SOAP與Web services,http://2tigers.net/html/tiger_column/article3.html
2. 孟巖,Web Service : WebOS中的Function Call,http://www.mengyan.org/blog/archives/2006/06/09/125.html
3. Axis學習筆記,http://www.javaresearch.org/article/showarticle.jsp?column=5&thread=29576
4. Google, Google SOAP Search API, http://www.google.com/apis/
5. Patrick Chanezon, Patch For Google APIs to handle proxy settings, http://www.chanezon.com/pat/google_proxy_patch.html
6. Hilton,關于Google API的學習,http://hedong.3322.org/archives/000274.html
7. Gopalakrishnan U、Shreevidya Rao,通過Axis2開發Web服務,http://www-128.ibm.com/developerworks/cn/webservices/ws-webaxis1/index.html
8. joyeta,Apache Axis2(java web service)備忘記,http://blog.matrix.org.cn/page/joeyta?entry=apache_axis2_java_web_service