簡易物件存取通訊協定 (SOAP):SOAP的應用(轉)
最後更新:2017-02-28
來源:互聯網
上載者:User
對象|訪問 簡易物件存取通訊協定 (SOAP):SOAP的應用
SOAP,是由全球資訊網聯盟(W3C)制定的的一個新通訊協議:Simple Object Access Protocol(中文:簡易物件存取通訊協定 (SOAP))的英文縮寫,目前已經得到IBM 、Ariba 、Commerce One 、SAP 、康柏、惠普等公司的支援。它能夠讓不同應用程式之間通過HTTP通訊協議,以 XML格式互相交換彼此的資料。由於HTTP通訊協議在網路上無所不在,而且XML解析程式又相當容易取得,所以SOAP能夠很容易地被套用與開發。當然這些便利性是有代價的:犧牲了部份運行速度,因此SOAP本身並不是用來代替原有的低級程式,但是如果程式設計師的主要考慮在於能夠很容易地與其它系統相互溝通,那麼SOAP的確能夠發揮它的功效。SOAP 開發工具在許多開發環境下已經可以取得了,包括 Python,Java,Visual Basic,Perl。本身具備遠端程序呼叫 API 程式(例如 Java 的 RMI 或者微軟的 COM+)開發經驗的程式設計員將會發現SOAP開發工具使用起來有一種類曾似曾相識的感覺。
在這裡我向大家介紹如何使用 Perl程式語言來開發網路服務(Web services),以及如何在SOAP伺服器上面建立應用程式。
首先到http://www.soaplite.com 下載SOAP::Lite工具程式,它是一個Perl程式模組,只要安裝好這套模組以及相關的函式庫(相關資料地址:http://www.soaplite.com/#PREREQUISITES),大家便可以開始編寫SOAP 服務程式了。
在開始設計一個SOAP傾聽程式(listener)之前,我們得先瞭解一下SOAP如何處理來自用戶端的請求。首先用戶端會送出一個 XML檔案給伺服器,稱為「SOAP 封裝(envelope)」。伺服器在接收到這個檔案以後會分析這個檔案,讀取檔案內含的類別名稱(class name)與函數名稱(function name),並且在這些名稱與特定的Perl程式對象之間建立對應關係。在下面的範常式序中,我們建立一個稱為World的類別,內含兩個函數 HelloWorld 與 GoodbyeWorld:
package World;
sub new {
bless {}, shift;
};
sub HelloWorld {
my ($self) = @_;
return "Hello World\n";
};
sub GoodByeWorld {
my ($self,$adjective) = @_;
return "Goodbye $adjective World\n";
}
1;
雖然我們不太可能實際看見一個SOAP請求(request)長得是什麼樣子,但是瞭解這些SOAP請求內容的幕後工作方式,對於程式的偵錯將會很有協助。在這裡,我們用下面這個非常簡單的例子來說明SOAP用戶端如何對前面提到的World類別提出請求,並且呼叫裡面的 HelloWorld 函數:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENC=http://schemas.xmlsoap.org/soap/encoding/
SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi=http://www.sorw.org/2001/XMLSchema-instance
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.sorw.org/2001/XMLSchema">
<SOAP-ENV:Body>
<namesp1:HelloWorld xmlns:namesp1="World"/>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
你可以在這個XML檔案中很清楚地看見封包與主體(body)開始的地方:HelloWorld 函數是在 body 裡面被呼叫的。在該行敘述中,命名空間(namespace)屬性的值就是我們要呼叫的函數的名稱,而XML命名空間(XML namespace)屬性的值就是該函數所隸屬的物件類別的名稱。在這個例子裡面,我們呼叫了World物件類別的 HellowWorld 函數。當我們要呼叫 GoodByeWorld 函數的時候,大部分內容都不需修改,只要將 body 的部分稍作修改即可:
<SOAP-ENV:Body>
<namesp2:GoodByeWorld xmlns:namesp2="World">
<c-gensym9 xsi:type="xsd:string">cruel</c-gensym9>
</namesp2:GoodByeWorld>
</SOAP-ENV:Body>
由於SOAP本身是通過HTTP通訊協議來傳遞,因此我們可以直接利用Perl本身提供的Web伺服器相關功能。首先編寫一個簡單的CGI程式,這個程式會把接收到的請求傳遞給我們之前寫好的World類別,並且把SOAP產生的響應資訊回傳給瀏覽器。在開始執行之前請別忘記確認你的伺服器支援CGI程式,並且要把該程式的許可權設定為允許執行。下面這個CGI程式會接收SOAP請求,並且傳遞給我們之前寫好的World類別:
#!/usr/bin/perl
use SOAP::Transport::HTTP;
use World;
SOAP::Transport::HTTP::CGI
dispatch_to('World')
-> handle;
我們要做的就只有這些,剩下的部分全都交給SOAP模組來處理就行了。你必須為每個你打算呼叫的SOAP類別都分別寫一個類似上面的CGI程式。此外要注意的是,在上面的 dispatch_to() 方法裡面所用到的參數就是你想要連結的SOAP類別的名稱。在編寫SOAP類別的時候要注意這些類別必須和其它類別一樣,一定要有一個名為 new 的方法(method)$self來做為呼叫其它方法時所使用的第一個參數。把封裝名稱(package name)放在程式碼的第一行,然後把這個模組以 .pm 做為副檔名儲存起來(請參考前面提到的World類別範常式序)。
SOAP::Lite 也可以根據所要求的名稱來動態載入不同的模組,這項功能可以讓我們編寫一個能夠載入某個目錄中任何一個模組的CGI程式。這種做法比較缺乏安全性,而且也比較不容易控制究竟要載入哪個模組,不過把各個SOAP模組統一放置在同一個目錄下,在檔案管理上的確會比較方便。要動態載入不同的SOAP模組,我們必須把相關的 use 敘述拿掉,並且把存放SOAP模組檔案的目錄路徑當成dispatch_to() 方法的第一個參數:
#!/usr/bin/perl
use SOAP::Transport::HTTP;
SOAP::Transport::HTTP::CGI
dispatch_to('/home/httpd/soap_modules/')
-> handle;
SOAP用戶端程式就像SOAP伺服器程式一樣都很容易編寫。你只需要載入 SOAP::Lite 模組,並且知道一些遠程服務(或者說「端點 endpoint」)的相關資訊就行了。事實上,收集遠程服務的相關資訊可能正是最困難的部分。你必須知道遠程伺服器的URL,伺服器所提供服務內含方法的命名空間URI,以及這些方法的名稱與需要傳入的參數。一旦取得了這些資訊,我們就可以開始編寫一個SOAP用戶端程式了。在下面的範常式序裡面,我為前面剛建立好的SOAP伺服器寫一個用戶端程式:
use SOAP::Lite;
my $s = SOAP::Lite
->uri('World')
->proxy('http://soapserver.mycompany.com/soap/soapserver.cgi')
->HelloWorld();
print $s->result();
my $s = SOAP::Lite
->uri('World')
->proxy('http://soapserver.mycompany.com/soap/soapserver.cgi')
->GoodByeWorld("cruel");
print $s->result();
在這個程式裡面,uri 接受的參數是遠程伺服器上面我們打算呼叫的類別名稱。但是並非每個SOAP伺服器在實際運作上都遵循這個慣例,因此你可能必須另外確認一下這裡的URI所應該使用的正確值。proxy 方法接受的參數是遠程伺服器上面的SOAP處理常式(handler)的 URL。在每一次試圖聯機到伺服器的時候都必須要提供前面提到的URI以及 proxy,才能夠正確聯機成功。最後我們便可以呼叫遠程伺服器上面的方法了,在這個例子裡面我們呼叫了 HelloWorld() 與 GoodByeWorld("cruel") 這兩個方法,並且通過 result() 函數來取得伺服器的響應資訊。請留意雖然我們呼叫的兩個方法都是來自於World這個類別,但是在這裡我們通過兩次獨立的交易來建立了兩個World類別的實體(instance)。這表示兩個實體之間並無法得知彼此目前的狀態,因此它們之間無法相互溝通。舉例來說,你不能在其中一個實體上面設定一個class的值,然後試圖在另一個實體上面取得這個值。
SOAP 服務程式可能還會要求用戶端提供一個特定的 SOAPAction 欄位,這個參數會通過HTTP表頭來傳送。要設定這個參數的值,你可以使用 on_action 方法來蓋過預設的處理方式。請看下面這個範常式序:
my $s = SOAP::Lite
->uri('World')
->on_action(sub { return "/Action#Action" })
->proxy('http://soapserver.mycompany.com/soap/soapserver.cgi')
->GoodByeWorld("cruel");
print $s->result();
在實際運作中,如果你需要瞭解一些偵錯資訊,SOAP::Lite 模組提供了一個選項來觀看用戶端與伺服器之間通訊狀況的詳細內容。這個選項會顯示整個請求過程的詳細資料,在追蹤程式錯誤的時候非常有用。錯誤資訊最常出自於不正確的URI或者 proxy 設定值,這些資訊都會出現在SOAP封包(packet)的文字內容裡面。要使用這項功能,只要在 use SOAP::Lite 敘述後面加上 +trace => all,就可以把偵錯資訊顯示在標準錯誤輸出串流(STDERR output stream)上面了。
use SOAP::Lite +trace => all;
my $s = SOAP::Lite
->uri('World')
->proxy('http://soapserver.mycompany.com/soap/soapserver.cgi')
->GoodByeWorld("cruel");
print $s->result();
SOAP::Lite 模組也提供了一個叫做 Autodispatch 的功能,它可以讓你在Perl程式裡面直接呼叫遠程伺服器提供的方法。一旦啟動了 Autodispatch 功能,當你呼叫程式裡面沒有定義的方法的時候,這些呼叫都會自動被傳送到遠程伺服器並且在上面執行。Autodispatch 功能讓SOAP不留痕迹地整合在Perl程式裡面,只要連結上遠程伺服器,之後就可以直接呼叫伺服器上面提供的各種方法,而不需要先參照到SOAP對象。
use SOAP::Lite +autodispatch =>
uri=>"World",
proxy=>'http://soapserver.mycompany.com/soap/soapserver.cgi';
print HelloWorld();
print GoodByeWorld("sweet");
在上面這個程式裡面,由於 HelloWorld() 與 GoodByeWorld 這兩個方法在我們的Perl程式裡面都沒有定義,因此它們會直接被傳送到 proxy 所設定的遠程伺服器上面去執行。使用 Autodispatch 功能就像是繼承其它的類別一樣,因此在程式裡面呼叫遠程伺服器提供的方法的時候,請先確認遠程伺服器上面的確已經定義好這些方法以供使用了。
小結:
在現實中,通過Perl使用SOAP是一件很容易的事情。不論建立伺服器或者編寫一個用戶端來向伺服器提出請求,都不需花費什麼心機。在對SOAP有一定瞭解時,相信你一定可以建立新的Web服務程式,或者直接利用其它SOAP伺服器提供的服務,提升你的網站功能