http://www.dreams.idv.tw/~code6421/Doc/Deploy.htm
Write By 黃忠成(Code6421)
八、 Service、ISAPI 、Apache DSO Write By 黃忠成(Code6421) 2002/10/15 於台北 截至目前為止,我們的程式都是執行於IntraWeb 所附的Web Server 之上,雖然這個Web Server 功能不錯,既可以安裝成Windows Service,又能在DELPHI IDE 中直接對程式除錯,但她畢竟只是 一個小型的Web Server,其功能與效能還是不及市面上的Server 級產品。當程式功能越來越多, 亦或是使用的人數增加時,這個Web Server 的效能可能就會讓使用者對你的程式抱怨連連。 這時我們就需要考慮將程式安裝到一個完整的Web Server 上了。 基於DELPHI WebBroker 對 Web Server 的支援,IntraWeb 允許你將程式轉換為ISAPI、DSO 模式,分發至IIS 或Apache 上, 其轉換步驟也相當簡單,只需變動幾行程式碼就可完成。這一章我們就以在第三章所討論的 JavaScript 運用的程式為範例,分別討論如何將程式安裝成Service 與如何建立可分發至IIS及 Apache 上的模組。 將程式安裝成Windows Services (服務) 在IntraWeb 中,只要是使用Stand-alone 方式建立的程式,都可以安裝成Windows Service,讓管理者 可以經由Services Manager(服務) 的設定來控制是否在開機時一併執行程式,藉此省掉登入系統的步驟。 要將程式安裝為Windows Service,你必須先確認位於ServerController 中的幾個重要屬性是否設定正確, 下面是這些屬性的列表及說明: 屬性
說明
Description
在Services Manager 中顯示於名稱位置的字串。
AppName
服務的名稱,注意! 字串中不能有空白。
Port
當程式被啟動後,其繫結的Port。
在這些屬性中,最需要注意的是Port 屬性值,這個屬性值在預設情況下是0,也就代表著程式啟動時 會以亂數產生一個數字,而後將程式繫結至這個Port 上,其結果可想而知,沒有人知道真實的Port 是多少,當然也無人可訪問這個網站了。將這些屬性設定妥當並編譯後,你就可以以命令列的方式 將程式安裝至Windows Services,其格式如下: -install
需要反安裝時,只須將-install 改為-uninstall 就可以將程式由Windows Services 中移除。 執行安裝命令後,假如沒有錯誤的話,系統會顯示出Service 已安裝成功的訊息,如果沒有這個訊息, 那代表著設定上有錯誤而導致安裝失敗。另外一點要注意的是,安裝後Service 並沒有立即啟動, 而是要等到下次開機時才會啟動,這時你可以開啟Services Manager 手動將這個Service 設定為啟動 狀態。 Stand-Alone Server And SSL 原本想列出SSL 的申請至安裝流程,無奈OpenSSL 未提供編譯好的版本,我的電腦環境又剛重裝過, 壓根兒就還沒裝C/C ,只好暫時作罷! 建議讀者們可自行至www.openssl.org 取得相關的原始碼,編譯後 在網路上搜尋OpenSSL 應可找到許多相關的寶貴資訊。 在這裡我就以IntraWeb 公司所提供的測試用SSL 認證檔案來介紹用法,你可以由下面這個URL 下載這個檔案: http://www.atozedsoftware.com/downloads/intraweb/SampleSSLCerts.zip 解開後請將這些檔案放到程式所在目錄,並按下表修改檔名: 原檔名
新檔名
CACert.pem
Root.pem
WSScert.pem
Cert.pem
WSSKey.pem
Key.pem
完成後請開啟專案,設定位於ServerController 中的SSLPort 值為443(SSL 預設使用的Port,如果電腦上有安裝 IIS or Personal WebServer,記得先將她們停止掉,否則會產生Port 無法繫結的訊息),接著設定SSLCertificatePassword 為aaaa(這個認證的密碼),最後編譯後執行程式,點選位於Run 中的Use SSL,最後再點選Run 中的Execute 來啟動瀏覽器,下面是執行於SSL 下的畫面: 有關如何取得SSL 及設定的部份,請各位至www.openssl.org 以及認證中心取得相關資訊,網路上也能找到許多 資料。 建立ISAPI 模組 要將原有的Stand-Alone 程式轉換為ISAPI,其首要動作就是先複製IWScriptDemo.dpr 成一個新的檔案, 請將這個檔命名為IWScriptDemoISAPI.dpr,並修改成下面這個樣子: library IWScriptDemoISAPI; {PUBDIST} uses IWInitISAPI, ServerController in 'ServerController.pas' {IWServerController: TDataModule}, uMain in 'uMain.pas' {formMain: TIWForm1}, uMenu in 'uMenu.pas' {frmMenu: TFrame}, uNumEdit in 'uNumEdit.pas' {formNumEdit: TIWAppForm}, uMinEdit in 'uMinEdit.pas' {formMinEdit: TIWAppForm}, uCSCalc in 'uCSCalc.pas' {formCSCalc: TIWAppForm}, uRotateImg in 'uRotateImg.pas' {formRotateImg: TIWAppForm}, uCursorMove in 'uCursorMove.pas' {formCursorMove: TIWAppForm}, uDefaultValue in 'uDefaultValue.pas' {formDefaultValue: TIWAppForm}, uDarkStar in 'uDarkStar.pas' {formDarkStar: TIWAppForm}, uChangeLink in 'uChangeLink.pas' {formChangeLink: TIWAppForm}, uRightEdit in 'uRightEdit.pas' {formRightEdit: TIWAppForm}; {$R *.res} begin IWRun(TFormMain, TIWServerController); End.
粗體字的部份代表修改的位置,我們只修改了兩個地方,第一個是將原本編譯為執行檔的部份改為 編譯成DLL。 第二個地方則是將原本含入IWInitStandAlone 改為IWInitISAPI,存檔之後於DELPHI 中開啟這個Project 編譯後就產生了可分發至IIS 的ISAPI 模組了。 雖然IntraWeb 的官方說明文件與FAQ 中都是這樣告訴你的,但是事實卻非如此。 當你使用瀏覽器 訪問這個程式後,會發現到程式有問題,不管點選那個連結,都會引發下面這個錯誤: 這是因為我們在程式中大量使用繼承所帶來的後遺症,只是為何在Stand-Alone 模式中可以正常執行呢? 經使用CPU Window 追蹤程式後,我認為這是IntraWeb 的Bug 所致,那麼該怎麼解決這個問題呢? 總不能不用繼承吧? 這可是很有用的技術啊! 解決方法很簡單,只需要將繼承的架構修改一下就可以了, 下圖是目前這個程式所使用的繼承架構: 圖中可以看到,Form1 及Form2 都是繼承至TIWMainForm 而來,這種方式在ISAPI 就會引發錯誤。 解決方法是改變原來的繼承架構,只要將繼承架構修改成下圖的樣子,就可以避開這個問題: 圖中可以清楚的看到,原來的TIWMainForm 已不再是Form1、Form2 的父類別,而改由TIWBaseForm 代之, 這種架構可以解決先前所遭遇到的問題。 當然,我們的程式已經完成了,如果照著圖所示改變繼承架構,似乎顯得有點麻煩。沒關係,山不轉路轉, 只要稍微變通一下,還是可以以最少修改來改變這個架構。只需新增一個新的繼承至TIWMainForm 的FORM, 再用她取代原本TIWMainForm 所做的事就完成了,下面是修改過的Project 程式碼: library IWScriptDemoISAPI; {PUBDIST} uses IWInitISAPI, ServerController in 'ServerController.pas' {IWServerController: TDataModule}, uMain in 'uMain.pas' {formMain: TIWForm1}, uMenu in 'uMenu.pas' {frmMenu: TFrame}, uNumEdit in 'uNumEdit.pas' {formNumEdit: TIWAppForm}, uMinEdit in 'uMinEdit.pas' {formMinEdit: TIWAppForm}, uCSCalc in 'uCSCalc.pas' {formCSCalc: TIWAppForm}, uRotateImg in 'uRotateImg.pas' {formRotateImg: TIWAppForm}, uCursorMove in 'uCursorMove.pas' {formCursorMove: TIWAppForm}, uDefaultValue in 'uDefaultValue.pas' {formDefaultValue: TIWAppForm}, uDarkStar in 'uDarkStar.pas' {formDarkStar: TIWAppForm}, uChangeLink in 'uChangeLink.pas' {formChangeLink: TIWAppForm}, uRightEdit in 'uRightEdit.pas' {formRightEdit: TIWAppForm}, uHome in 'uHome.pas' {formHome: TIWAppForm}; {$R *.res} begin IWRun(TFormHome, TIWServerController); end.
重新編譯後分發至IIS 上,你會發現問題不見了。 不過別太高興,事情並未結束,問題發生在你位於FROM 1, 然後點選了往FORM 1 的連結,你所厭惡的錯誤訊息又回來了。 這個問題與繼承架構無關,全都是 IntraWeb Cache 機制惹的禍。 要解決這個問題的方法目前只有一個,就是對Move 這個函式做點手腳: procedure TfrmMenu.Move(AFormClass: TIWAppFormClass); begin if (TIWAppForm(RWebApplication.ActiveForm).ClassType <> AFormClass) then begin TIWAppForm(RWebApplication.ActiveForm).Release; AFormClass.Create(RWebApplication).Show; end; end;
重新編譯與分發後,程式終於可以正常的執行了。只是我很好奇,為何如此嚴重的問題沒有被修正,而且 這些日子來我常常在IntraWeb 的新聞群組流連,此問題也被提出不只一次了,但總是沒有看到有用的回答 (呵……他們都要你改往Peer-Support 的新聞群組去提問……)。 不管如何,至少目前這個解決方法是可行的。 PS: 在我仔細的觀看IntraWeb 的更新記錄後,發現到他們應該已經知道這個問題,所以才會由5.0.43 一直 改到5.0.53,只是結果還是沒改好(5.1 好像已經修正了,不過目前我還沒裝起來測試)。 對ISAPI 除錯 對ISAPI 除錯一直都是屬於FAQ 級的問題,其實答案很簡單,只要稍微設定一下,我們就可以 在DELPHI IDE 中除錯ISAPI 的程式。 首先請開啟IIS Manager,新增一個虛擬目錄: 輸入別名後按下一步。 將目錄設定為程式所在的目錄。 記得將執行的權限打開。 完成後請點選剛建立的目錄,選擇內容後將應用程式保護設定為隔離式。 完成後請關閉IIS Manager,開啟元件服務來設定COM 。 請點選你剛設好的項目,選擇內容。 這裡要將應用程式識別碼複製下來,在DELPHI 中我們需要這個資訊,完成後切換到識別碼頁,將帳戶 改為互動式使用者。 這樣整個設定就完成了,接著只要回到DELPHI 中開啟ISAPI Project 後設定Run Parameters 就可以了。 完成後你就可以設定所要停下的中斷點,執行後使用瀏覽器開啟這個網頁,只要經過你所設的中斷點, 程式就會停下來了。 更簡單的方法 雖然上面所說的方法是可行的,但步驟上還是稍嫌麻煩了些,eliteDevelopments 公司提供了一個On-Complie Helper 來簡化這個工作,只是她是商業型的程式,必須付費才能使用,不然你只能使用評估版的,缺點是每次啟動都要 等10 秒…….網址是:www.elite-dev.com。 建立DSO 模組 有了轉換成ISAPI 的經驗,要把程式改變為DSO 模組就顯得簡單多了,一樣複製一個新的Project後修改成 下面的樣子: library IWScriptDemoApache; {PUBDIST} uses ApacheApp, IWInitApache, ServerController in 'ServerController.pas' {IWServerController: TDataModule}, uMain in 'uMain.pas' {formMain: TIWForm1}, uMenu in 'uMenu.pas' {frmMenu: TFrame}, uNumEdit in 'uNumEdit.pas' {formNumEdit: TIWAppForm}, uMinEdit in 'uMinEdit.pas' {formMinEdit: TIWAppForm}, uCSCalc in 'uCSCalc.pas' {formCSCalc: TIWAppForm}, uRotateImg in 'uRotateImg.pas' {formRotateImg: TIWAppForm}, uCursorMove in 'uCursorMove.pas' {formCursorMove: TIWAppForm}, uDefaultValue in 'uDefaultValue.pas' {formDefaultValue: TIWAppForm}, uDarkStar in 'uDarkStar.pas' {formDarkStar: TIWAppForm}, uChangeLink in 'uChangeLink.pas' {formChangeLink: TIWAppForm}, uRightEdit in 'uRightEdit.pas' {formRightEdit: TIWAppForm}, uHome in 'uHome.pas'; {$R *.res} exports apache_module name 'IWScriptDemoApache_module'; begin IWRun(TFormHome, TIWServerController); end.
exports 部份是要在Apache 中使用的module 名稱,通常我們都會將原有的名稱加上_module 做為module 的名稱。 編譯後會產生一個DLL檔,請將它放到Aapche 所在的libexec 子目錄下,接著修改http.conf 加入下面的設定: LoadModule IWScriptDemoApache_module libexec\IWScriptDemoApache.dll SetHandler IWScriptDemoApache-handler
完成後啟動Apache,在瀏覽器上鍵入http://yourIP/scriptdemo 就可以開啟你的程式了。 IntraWeb 對於Apache 的支援還是有些Bug,這個Bug 發生在Apache Server 所使用的Port 非80 與 使用tmURL 方式來處理Session時,於URL 重導後原有的Port 設定會被清掉,使得無法正常的 訪問該網頁。 解決方法是將位於ServerController 中的SessionTrackingMethod 設為tmCookie,這樣 就可以避開這個問題了。 或許你還對ISAPI 時所發生的問題有點疑惑,這個問題在DSO 中是否還會發生? 答案是肯定的, 會! 一模一樣。 後記 在我的計劃中,這一篇文章是在全文的第八章,也就是說如果照我原定的計畫走的話,那你可能要 等上好一陣子才會看到這一篇,這不是我所樂見的,所以在衡量輕重後,決定將這篇文章提前公佈於 網路上,希望對你會有幫助。
不貼庵怕忘記 哈哈