你应该先用 appmode 开发(这样好调试),到最后发布时按如下方法修改分发。
八、 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,其格式如下:
<AppName> -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<Location /scriptdemo> SetHandler IWScriptDemoApache-handler</Location>
完成后激活Apache,在浏览器上键入http://yourIP/scriptdemo 就可以开启你的程序了。
IntraWeb 对于Apache 的支持还是有些Bug,这个Bug 发生在Apache Server 所使用的Port 非80 与
使用tmURL 方式来处理Session时,于URL 重导后原有的Port 设定会被清掉,使得无法正常的
访问该网页。 解决方法是将位于ServerController 中的SessionTrackingMethod 设为tmCookie,这样
就可以避开这个问题了。
或许你还对ISAPI 时所发生的问题有点疑惑,这个问题在DSO 中是否还会发生? 答案是肯定的,
会! 一模一样。
后记
在我的计划中,这一篇文章是在全文的第八章,也就是说如果照我原定的计画走的话,那你可能要
等上好一阵子才会看到这一篇,这不是我所乐见的,所以在衡量轻重后,决定将这篇文章提前公布于
网络上,希望对你会有帮助。