第17章_使用WebBroker组件创建Web服务器

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第17章使用WebBroker组件创建Web服务器
WebBroker是一套VCL工具,可以帮助您建立Web服务器程序。

WebBroker 与Delphi企业版一同发布,也可单独购买并与Delphi专业版配合使用。

WebBroker可用于建立Web服务器,支持ISAPI、NSAPI或CGI协议。

ISAPI (Internet Services API)和NSAPI(Netscape Services API)通过TISAPIApplication Web应用程序组件来支持。

CGI(Common Gateway Interface)通过TCGIApplication Web应用程序组件来支持。

Web服务器Apache 是通过新的TApacheApplication组件来支持。

对于开发者来说,这意味着使用对大多数Internet服务器可用的通用协议编写Web程序更为容易。

本章我们将特别注重用于建立Web服务器的组件,它们位于Internet属性页上。

所有的Web服务器都包含一个TWebModule组件,或者是一个TDataModule 和一个TWebDispatcher组件。

在讨论这些组件之前,我们先快速浏览一下HTML 的基础知识。

理解URL(Uniform Resource Locator)请求和HTML页面的基本结构是很有必要的,因为用户会调用Web服务器,而Web服务器要提供Web页面服务。

17.1 HTML基础
Web服务器是URL路径的一部分。

WebBroker服务器将基于URL请求的内容和Web服务器的设计返回HTML页面。

通常,这些响应都是以HTML文档的形式进行。

文档可能会包括到其他Web站点或Web服务的超链接。

本节包含了对URL分解、HTML文档和可替换参数标记的简要综述,这些机制有助于返回动态Web页面。

17.1.1 URL(Uniform Resource Locator)
URL由协议标签、主机名、脚本或服务器程序、路径信息和一些由用户向服务器提供的查询信息构成。

参见下面的代码和图17.1,可以看到一个URL的各个部分,该URL指向如图所示的Web服务器。

http://localhost/scripts/iserver.dll/runquery?CustNo=1645
本例中,所用协议为HTTP,即超文本传输协议(Hypertext Transfer Protocol)。

HTTP可能是最常用的浏览器协议,但从第16章是可知,并非只有这一种可能(回忆第16章,可以知道有几种TCP/IP协议,像FTP和安全HTTP,都可以用作URL中的协议)。

例子中的主机名是LocalHost,它代表客户机。

430 Delphi 6应用开发指南
LocalHost也是计算机名或IP地址127.0.0.1(127.0.0.1也称为回送IP地址)。

主机名可以是任何IP地址或DNS表中的名字;例如、
或。

URL的脚本部分是可选
图17.1 URL在Web浏览器的地址栏中输入,也可
能出现在HTML文档中的HREF标记之后
的。

对Web服务器而言,即包含服务器程序的文件夹。

如果在Windows 2000系统下运行IIS或在PC上运行Peer Web Services,那么默认情况下脚本位于c:\inetpub\scripts目录(见图17.2)。

服务管理器将虚拟路径脚本映射到物理上的目录。

脚本后紧接着是服务器程序。

本例的服务器程序是iserver.dll。

例子中的路径信息由run-query表示。

最后一部分信息示范了如何向服务器发送查询参数。

在例子中,CustNo=1645将发送到服务器程序。

图17.2 Windows 2000 专业版系统中Scripts Properties对话框,
可以看到虚拟的脚本路径被映射到物理路径
注意:本例中所示的请求摘自Delphi中的例子iserver.dpr,该工程位于¥(DELPHI)\Demos\WebServ\IIS文件夹中。

上文中的请求是对biolife.db表
发出的,该文件是Delphi附带的。

 
您可能已经熟悉协议标签加上主机名的请求类型。

但如果您对电子商务有一定程度的了解,例如在进行购物,您可能已经看到过另外一些URL 请求类型。

注意:最熟悉的URL形如http://www.digitalblasphemy.com,在请求中不
存在路径、脚本、查询和特定的页面信息。

只涉及到Web服务器上的一个页面。

Microsoft公司的Web服务器IIS在默认情况下返回default.asp页面,
但可以进行配置以返回任何页面。

http://www.softconcepts.com站点返回
的页面是index.htm。

默认页面是可配置的。

管理和配置IIS或其他Web服
务器已经超出了本书的范围;但在这方面有很多书籍可供参考。

 
如果给出了Web站点和路径来运行脚本(例如上文例子中的runquery)但没有找到,则Delphi的WebBroker组件允许指定默认路径。

按照惯例,本章中的默认路径是/root。

17.1.2 基本的HTML结构
上一节中的请求是要求WebBroker服务器返回特定页面。

如果提供查询信息,则页面内容可以由查询值来控制。

可以通过设计,对用户屏蔽Web页面的细节,如CustNo,这是个好主意,把细节嵌入到HTML源文件中即可完成;而用户可通过输入URL直接发送请求。

无论如何,基本的HTML页面的结构都是一致的。

提示:HTML(Hypertext Markup Language)中包括标记,标记语言的读者
可以认为这些标记是指令。

 
注意:请记住,页面可能会非常复杂。

其中可能包括Active Server Pages
和JavaScript或VBScript,而且像FrontPage这样的页面设计工具可能会
添加相对数量和种类的修饰。

不考虑这些修饰,HTML页面包含了某些一致的
元素。

 
基本的HTML页面由标记组成,它们定义了文档的结构。

许多标记是对称的,包括开始标记和结束标记。

例如,HTML文档以<html>标记开始,结束标记为</html>(请注意,/用于结束标记)。

在文档标记之内是文档体标记<body>和</body>。

通常所看到的文档内容是在文档体标记之内定义的。

下面列出的代码使用<html>和<body>标记示范了框架性的Web页面,与本书开头的Hello World 程序差不多。

<html>
<body>
Welcome to Valhalla Tower Material Defender!
</body>
</html>
上述Web页面是无法得到任何“本年度××Web站点”奖励的,但它确实示范了HTML的简单的和基本的特性。

作为练习,打开notepad.exe并输入上面的代码。

将文件保存为hello.htm。

然后打开Web浏览器。

单击File | Open并浏览hello.htm的位置,再单击OK。

可以看到,浏览器中显示了文档体标记之间的文本(五、六年前这可是件了不起的事情)。

还有许多标记以及使得这些标记易于使用的工具,但你还是可以使用简单的文本编辑器。

下面示范了常用的其他标记,可以帮助您入门。

定制文档体
可以向文档体添加额外的特征。

使用<bgcolor>标记,可以将页面的背景颜色指定为颜色名或十六进制数字。

在文档体标记中,还可以指定背景图像。

下面对文档体标记进行了修改,示范了背景颜色和背景图像的使用。

注意:本章中的HTML文档使用Notepad.exe生成,并在Internet Explorer 5.5上进行了测试。

无法保证其他的特定Web浏览器或早期版本是否能够对
这些超文本标记进行渲染。

 
<body bgcolor=#00FFFF>
<body background="bubbles.bmp">
背景颜色由颜色名或48比特的RGB(红、绿、蓝各16比特)颜色表示。

颜色数字由三个十六进制数组成,各16比特。

这里没有设置红色的比特位,而设置了所有的绿色和蓝色比特位。

可以用颜色名cyan或blue-green来替换上述的颜色值。

Background属性指向一个图形文件,该文件将在文档的背景上绘出。

有许多标记,一些标记有各种属性,特定的浏览器可能支持其中的全部或一部分。

由于标记的种类和属性很多,因此需要使用Web页面设计程序如FrontPage 或Hot Metal等(该程序与某些版本的Delphi捆绑发行)。

使用水平规则
具有3D效果的线由水平规则标记<hr>表示,该标记指示浏览器在HTML文档体中绘出一条具有浮雕效果的线。

行结束和段落标记
在HTML文档体中文本结束处的<br>将向文本插入一个硬回车。

如果在文档体中使用<p> </p>标记,浏览器会在该位置创建段落。

例如,
<html>
<body>
This is <p>some</p> text.
</body>
</html>
在Web页面中显示如下:
This is
Some
Text.
可以使用<br>、<p></p>以及<pre></pre>标记格式化文档中的文本。

最后一对标记是预格式化标记,它表示文本块在Web页面中的显示方式与其书写方式相同。

使用标题
<title></title>标记可以为页面指定标题。

标题标记通常位于<body>标记之前,在<html>开始标记之后。

下面的代码示范了标题标记。

<html>
<title>Hello World!<title>
<body>
Welcome to Valhalla Tower Material Defender!
</body>
</html>
上述HTML文档将在浏览器的标题栏显示文本“Hello World!”。

添加超链接
<A HREF="path">页面上显示的文本</A>标记用于向HTML文档体中添加超链接。

例如,
<A HREF=">Microsoft</A>
将显示带下划线的文字Microsoft,它是超链接。

用户单击该超链接时,浏览器将重定向到。

Web本身就是由数以百万计的页面组成,页面中可能包含指向其他页面的超链接。

实际上,每个页面都可以想像成Web的一个点,而每个超链接都是万维网的一条线。

请记住,超链接可能会指向Web服务,而服务再生成页面,我们在这里正是这样做的。

书签
书签标记表示为<A NAME="#text">text</A>,它可以作为Web页面的定位器,使用户可以在页面内移动。

使用<HREF>标记既可以表示当前页面内的位置,也可表示另外的页面中的位置。

下面是一些例子:
<A NAME="#location">Location Title</A>
<A HREF="/index.html#location>Goto Index.htm
Location</A>
<A HREF="#location">location</A>
注意:当键入的URL中有空格时,请在URL中使用空格字符的值(ASCII字
符32)。

字面上是%20,在十六进制中20是十进制的2*16,即32;在URL
中要使用空格之处插入%20即可。

 
上述例子的第一行定义了一个书签位置。

可以注意到前缀#。

在Web页面上会显示文本Location Title。

第二个例子打开位于的Web页面index.html,并定位到#location书签。

最后一个例子在当前页面内移动,因此并未给出页面位置。

插入图像
可以在Web页面中插入各种图像,包括GIF、JPEG或BMP格式。

<img src="图形文件路径">标记用于将图像嵌入到Web页面中。

可以向图形标记加入高度和宽度属性,以限制图像的大小。

alt属性用于指定Web页面在文本格式下用于替换图像的文本,其他情况下用于提示。

border属性用于指定图像周围边界的宽度。

这里有个例子:
<img src="image/bookimg.gif" height=150 width=100 border=1
alt="Building Delphi 6 Applications">
本例向Web页面嵌入了一幅GIF图像,150像素高、100像素宽、边界宽一个像素、提示为“Building Delphi 6 Applications”。

当鼠标移动到图像上时,将
显示包含alt文本的提示(在较新的浏览器中)。

格式化文本
HTML支持很多种文本格式,在一定程度上依赖于浏览器对特定边界的渲染能力。

通常,在大多数浏览器中可以使用较为简单的标记。

<i></i>标记表示标记之间的文本应该是斜体。

与此相似,<b></b>标记表示其中的文本显示为黑体;<u></u>对其中的文本添加下划线;而<s></s>标记向其中的文本添加删除线。

这里是一些例子:
<b>bold</b> yields bold
<i>italics</i> yields italics
<u>underline</u> yields underline
<s>strikethrough</s> yields strikethrough
文本格式化标记可以嵌入到其他种类的标记中,从而形成形式非常丰富的Web文档。

创建表格视图
有些浏览器支持帧。

帧可以对Web文档进行嵌套,看起来像是单一的文档,这里并不讨论该机制。

尽管许多浏览器支持帧,但许多Web站点是使用表格而不是帧制作的。

<TABLE>标记可以将页面的空间组织起来并划分为区域。

表格标记基本上支持对页面空间进行三维划分。

<TABLE></TABLE>标记定义了表格的边界。

<TR></TR>标记定义了表格中的一行,而<TD></TD>标记则定义了表格中一个单元。

另外,您还可以指定表格头,它表示每一列的标题信息;同时,表格还以进行n维嵌套。

可以想像到,这样的HTML文档看起来可能会复杂一些。

关于Web页面设计有许多出色的书籍,我们在这里只介绍表格标记的基本应用。

定义表格将HTML文档中的表格等价于电子表格或数据库表是有道理的。

HTML表格标记可以将页面划分为统一分割的区域。

一种用法是用来代表基于表
格的数据,另外还可以用于划分页面的区域和数据。

表格以<TABLE>标记开始,</TABLE>标记结束。

表格也可以嵌套。

例如,表格中的一个单元还可以包含另一个嵌套的表格。

表格还支持一些属性标记,用于定义表格的显示方式。

包括背景颜色、表格宽度、单元内部占位空间、单元距离以及边界宽度等。

宽度可以用像素数目或全部可用宽度的百分比来表示。

下面列出的代码(其页面显示如图17.3所示)示范了如何在表格标记中使用各种属性标记。

注意:本小节只强调了下面代码中的表格标记。

代码的其他方面将在其后的
三个小节中讨论,我们将继续引用该代码。

 
<html>
<body>
<Table BGCOLOR=#88EE88" WIDTH="75%" CellPadding=10 CellSpacing=1
图17.3 使用表格标记和相关属性进行格式化的文档
添加表格头表格头标记<TH>表示HTML表格的列标题。

请注意上面的代码,其中分别向表格的三列添加了列标题Column1、Column2、Column3。

定义表格行表格的每一行数据都使用<TR></TR>标记表示。

即使在HTML 源文件中标记之间包括了许多行文本也是如此,该标记指示浏览器将标记之间的所有东西都作为表格的一行数据来显示。

向表格添加数据单独的表格元素使用<TD></TD>标记表示,如代码所示。

由于单一的数据元素可以包含简单的文本或嵌套表,因此其工作方式非常简单。

请注意,<TD>标记可能会包含一些额外的属性,如代码中所示的ALIGN属性。

提示:为建立有趣的Web页面,一个好方法是复制已存在的页面,并进行定
制。

 
很明显,单独的标记是易于理解的。

HTML的潜在威力正在于这种简单性。

如同任何语言的语法,我们进行通信的能力受对语言的理解的限制。

虽然HTML 是简单的,考虑到26个拉丁字母——其可能性确实是令人吃惊的,正像World Wide Web一样。

如果需要创建高级的Web页面,还需要进一步学习,本节只是提供了进阶的基础。

17.1.3 将可替换参数标记与WebBroker一同使用
专业水准的Web页面需要更多的努力,并广泛地使用HTML,其内容远远超过这里所介绍的。

除了需要创建基本的Web页面之外,还需要表示在动态Web 页面中可替换的标记;这些标记将使用由Web服务器传送的动态数据替换。

可替换参数标记与书签标记看起来很相似。

可替换参数在Delphi的Web服务器页面中使用<#标记名>表示。

对于并不表示有效的超文本标记的< >对,HTML惟一的行为是忽略掉这些标记。

但Delphi 组件可以查找一些特定格式的文本。

注意:TPageProducers的TagString行为与Format函数行为非常相似。


遇到特定的标记时,就使用格式化文本替换该标记。

Format函数使用字符串
参数,以%开头,后接特殊的格式化字符;而HTML文档中遇到<#标记名>时,
则触发OnHTMLTag事件。

显然,一旦该类型事件发生,即可使用必要的代码
进行合适的替换。

 
当为Web服务器设计页面时,当需要向WebBroker页面插入数据时,只要找到<#标记名>参数标记即可。

TPageProducer组件的OnHTMLTag事件会传递一个TagString参数,可以将其与预先确定的值进行比较,然后根据TagString的值采取合适的动作。

下面一节示范了WebBroker组件一些基本的方法、特性和事件,可用于建立Web服务器。

17.2 使用WebBroker组件
Delphi的WebBroker套件定义了一些组件,能够对URL请求进行响应;这些URL请求是由浏览器或HTTP服务器应用程序向基于WebBroker套件建立的服务器发出的。

有一些基本的组件可以支持这种行为特征,而服务器的其余部分则是由您业已熟悉的组件构成的。

WebBroker支持建立ISAPI、NSAPI、CGI和Apache服务器。

ISAPI和NSAPI 服务器分别是由Microsoft和Netscape的Internet服务器支持的。

而Apache服务器则是一种流行的Internet服务器;Delphi 6的WebBroker组件也支持建立Apache服务器。

Delphi的WebBroker支持CGI服务器,可建立为单独的控制台程序或Windows程序,将请求返回到标准输入/输出设备。

大多数流行的浏览器都支持CGI。

图17.4 WebAction集合编辑器可以定义路径信息,
用于浏览器或其他来源发出的URL请求中
注意:当某个动作是默认动作时,忽略Enable特性。

默认动作总是可用的。

 
假定图中所示的Root动作是为驻留在LocalHost计算机上的ISAPI服务器server.dll定义的。

下面的两个URL都会返回由PageProducer1组件所定义的响应。

http://LocalHost/scripts/server.dll
http://LocalHost/scripts/server.dll/root
除了WebAction编辑器中所显示的信息之外,还可以指定MethodType。

默认的MethodType是mtAny。

默认的MethodType必须对任何请求进行响应,其他可能的MethodType包括mtGet、mtHead、mtPost和mtPut。

mtGet类型请求用于获取与URL关联的信息。

mtPut类型用于替换与URL关联的信息的内容。

mtPost用于将请求的内容发送到服务器。

最后,mtHead类型只返回请求的头信息。

当Web服务器从HTTP服务器接收到路径和查询信息时,首先从动作项列表中查找匹配的路径和MethodType。

如果没有匹配的动作,则使用默认动作。

另一方面,找到匹配动作后,则调用OnAction事件。

OnAction事件处理程序的参数包括:调用对象的引用、TWebRequest对象、TWebResponse对象和一个布尔类型的变量参数Handled。

TWebRequest对象Request包含了发送到HTTP服务器的请求的所有信息。

TWebResponse对象Response可用于将内容返回到服务器。

Content特性可用于返回简单的文本,而ContentStream和ContentType特性可用于返回较为复杂的二进制数据如图像或大块的文本。

变量参数Handled用于表示事件处理程序是否完全处理了该请求。

将Handled设置为False表示还需要其他处理程序来完成对请求的处理。

procedure TDataModule2.WebDispatcher1GetHeadAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse;
var Handled: Boolean);
const
sContent = '%s %s <BR> Connection: %s <BR> User-Agent: %s
<BR>' + 'Host: %s <BR> Accept: %s <BR>';
</body>
</html>
假定上面的HTML与例子中的默认URL路径Root相关联,那么在请求默认响应时,将对文档中的每个标记调用相关联的PageProducer1的OnHTMLTag 事件处理程序。

在例子中,只有一个HTML透明标记:<#CURRENTTIME>。

将TagString特性与已知的标记进行比较,可以对遇到的每个标记都提供替换文本。

下面列出的代码将TagString参数与CURRENTTIME标记进行比较。

当遇到CURRENTTIME标记时,即可如下例所示使用系统时间对其进行替换。

procedure TDataModule2.PageProducer1HTMLTag(Sender: TObject;
Tag: TTag; const TagString: String; TagParams: TStrings;
var ReplaceText: String);
begin
if( CompareText(TagString, 'CURRENTTIME') = 0 ) then
ReplaceText := TimeToStr(Now);
end;
提示:在比较标记字符串时,尖括弧和#符号被忽略。

<#和>的作用是使得标
记对HTML阅读器透明。

 
页面生成器的默认行为是使用空字符串替换不匹配的标记。

在TTag参数中含有枚举值,表示了发现该标记的上下文。

也可以向透明标记添加标记属性。

标记属性添加到TStrings类型参数TagParams,在OnHTMLTag事件处理程序中进行处理。

为示范TagParams参数的用法,下面分别对HTML文档和事件处理程序进行了修订:
<#CURRENTTIME DateTimeFormat=hh:nn:ssa/p>
修订的标记添加了一个参数,在本例中将作为标记的格式化规则。

修改后的事件处理程序考虑了标记参数的可能性。

procedure TDataModule2.PageProducer1HTMLTag(Sender: TObject; Tag: TTag; const TagString: String; TagParams: TStrings; var
ReplaceText: String);
begin
if( CompareText(TagString, 'CURRENTTIME') = 0 ) then
if( TagParams.Values['DateTimeFormat'] <> '' ) then
ReplaceText := FormatDateTime(
TagParams.Values['DateTimeFormat'], Now)
else
ReplaceText := TimeToStr(Now);
end;
修订后的代码检查是否存在DateTimeFormat参数。

如果该参数非空,则对
自动地替换为与标记名匹配的字段值。

由于代码只是把表打开,因此字段的值将是表中第一行所包含的值。

对Orders页面生成器进行微小的修改,即可使用浏览器的刷新按钮看到所有的订单。

在TDataSetPageProducer.OnCreate事件处理程序中打开相应的表。

在TDataSetPageProducer.OnDestroy事件中关闭表,在每次触发WebAction时将当前记录指针向前移动一个记录。

下面列出了修订后的代码。

procedure TWebModule1.WebModule1OrdersAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled:
Boolean);
begin
Response.Content := Orders.Content;
if Not TableOrders.Eof then TableOrders.Next
else TableOrders.First;
end;
procedure TWebModule1.OrdersCreate(Sender: TObject);
begin
TableOrders.Open;
end;
procedure TWebModule1.OrdersDestroy(Sender: TObject);
begin
TableOrders.Close;
end;
尽管这对于浏览所有的记录而言是一种呆板的方法,但它是可用的,而且可以作为更高级技术的基础。

看到多条记录的更为方便的方法是使用下一节中示范的TDataSetTableProducer组件。

17.2.4 查看表数据
TDataSetTableProducer组件用于返回多行数据。

它可以定义数据的表格视图(见图17.5),并在请求该路径时显示多行数据。

返回的实际行数由TDataSetTableProducer.MaxRows特性决定。

TDataSetTableProducer组件包括了许多用于描述和添加页面内容的特性,如Footer、Header、Caption和RowAttributes等。

如果只是简单地把TTable或TQuery对
象赋值给TDataSetTableProducer.DataSet特性,则页面上会显示数据集中所有的列。

可以选择使用列编辑器,只返回列的特定子集。

图17.5 HTML表格,其内容来自于ORDERS.DB数据,
是通过TDataSetTableProducer组件得到的
单击TDataSetTableProducer组件上下文菜单中的Response Editor菜单项,即可运行Columns编辑器(如图17.6所示)。

该编辑器与TDBGrid
的Columns编辑器非常相似。

但TDataSetTableProducer的Columns编辑器并不是把列值返回到VCL控件,而是生成必要的HTML文档,将其与根据选定的列得到的静态字段值合并起来。

图17.6 要创建如图17.5所示的HTML文档,可在Columns编辑器中如图配置
图17.5中所显示的示例页面在本书CD-ROM的MastApp.dll中定义。

通过在TDataSetTableProducer.OnFormatCell事件中修改背景颜色,即可产生该页面的效果。

OnFormatCell事件的代码如下所示:
procedure TWebModule1.ManyOrdersFormatCell(Sender: TObject;
CellRow, CellColumn: Integer; var BgColor: THTMLBgColor;
var Align: THTMLAlign;
var VAlign: THTMLVAlign; var CustomAttrs, CellData: String);
begin
if CellRow = 0 then BgColor := 'Gray'
else if CellRow mod 2 = 0 then BgColor := 'Silver';
end;
要创建所示的页面,可按照下列步骤进行。

1.单击File | New | Other命令,创建新的Web服务器程序,并创建ISAPI Web Server Application。

2.从组件模板的Internet属性页添加一个TDataSetTableProducer组件,从Data Access属性页添加一个TTable组件。

3.将TTable.DatabaseName特性设置为DBDEMOS。

4.将TTable.TableName特性设置为orders.db表。

5.将TDataSetTableProducer.DataSet特性设置为TTable组件。

6.将上面列出代码添加到TDataSetTableProducer.OnFormatCell事件处理程序。

7.在TWebModule上单击右键,然后在TWebModule上下文菜单中单击Action Editor菜单项。

8.添加动作项ManyOrders。

9.对动作项的PathInfo特性输入文本/ManyOrders。

确认该动作是可用的,并将Producer特性设置为TDataSetTableProducer组件。

确认Enabled特性设置为True(可以在Object Inspector中进行所有的改动)。

10.将工程保存为MastApp。

并建立该应用程序。

编译该ISAPI服务器并将其复制到Web服务器脚本目录(请记住,如果在计算机上你有Peer Web Services或在Windows NT下有IIS,即可测试该服务器)。

假定您是在Windows 2000系统上运行IIS,默认目录为inetpub,可以通过输入地址http://localhost/scripts/MastApp.dll/ManyOrders 来运行服务器。

下一节示范了TQueryTableProducer组件的用法以及用于响应URL中查询的TWebRequest对象。

17.2.5 TQueryTableProducer组件
TQueryTableProducer组件用于为TWebRequest.QueryFields特性中的GET 请求查询字段信息;POST方法的信息通过TWebRequest.ContentFields特性传递到服务器。

上述两个特性均为TStrings。

可以使用TStrings的Names和Values 刷新得到传递给服务器的数据。

为演示TQueryTableProducer组件,我们需要看一下位于$(DELPHI)\Demos\Internet WebServ\IIS文件夹下的iserver.dpr工程。

iserver.dpr 例子通过对DBDEMOS数据库中的Customer.db表进行迭代,使用TPageProducer组件生成顾客列表。

WebAction定义在main.pas中,以返回表示每个顾客的超链接列表。

procedure TCustomerInfoModule.CustomerListHTMLTag(Sender:
TObject; Tag: TTag; const TagString: String;
TagParams: TStrings; var ReplaceText: String);
var
Customers: String;
begin
Customers := '';
if CompareText(TagString, 'CUSTLIST') = 0 then
begin
Customer.Open;
try
while not Customer.Eof do
begin
Customers := Customers +
Format(
'<A HREF="/scripts/%s/runquery?CustNo=%d">%s</A><BR>',
[ScriptName, CustomerCustNo.AsInteger,
CustomerCompany.AsString]);
Customer.Next;
end;
finally
Customer.Close;
end;
end;
ReplaceText := Customers;
end;
TPageProducer类型的组件CustomerList将<#CUSTLIST>用每个顾客的超链接进行替换。

有一行特定的HTML语句是使用上面的事件处理程序中的Format语句生成的。

<A HREF="/scripts/%s/runquery?CustNo=%d">%s</A><BR>
%s参数是Web服务器程序的名字。

可以对该值进行硬编码,在数据模块创建时使用API过程GetModuleFileName来得到这个值就更为灵活。

procedure TCustomerInfoModule.DataModule1Create(Sender: TObject);
var
FN: array[0..MAX_PATH- 1] of char;
begin
SetString(ScriptName, FN, GetModuleFileName(hInstance, FN, SizeOf(FN)));
第17章使用WebBroker组件创建Web服务器447
ScriptName := ExtractFileName(ScriptName);
end;
注意:请记住,可以使用TTable或TQuery的字段编辑器在设计时生成TField
组件。

 
路径信息/runquery代表了一个动作项。

查询是?CustNo=%d,其中%d表示
整型参数,将使用CustomerCustNo.AsInteger来替换,并向用户提供超链接以及
从TField对象CustomerCompany读出顾客名。

在指向每个顾客的超链接组装好
以后,将使用这些链接替换ReplaceText变量参数。

当TPageProducer对象CustomerList使用顾客列表进行响应时,单击任意
的顾客超链接都会把CustNo发送到QueryAction项。

QueryAction项是动作项
的名字,由/runquery路径表示。

发送到/runquery动作项的请求出现在浏览器的
地址栏中,其形式如下(假定我们选中了Action Club链接):
http://localhost/scripts/iserver.dll/runquery?CustNo=1645
当向Web服务器提供路径时,将调用QueryAction.OnAction事件,并照原TQueryTableProducer对象CustomOrders的内容。

在事件处理程序的实现中,TQuery的Locate方法用于只返回与每个特定顾客相关联的订单。

procedure TCustomerInfoModule.WebModule1QueryActionAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse;
var Handled: Boolean);
begin
Customer.Open;
try
if Customer.Locate('CustNo',
Request.QueryFields.Values['CustNo'], []) then
begin
CustomerOrders.Header.Clear;
CustomerOrders.Header.Add(
'The following table was produced using a'+
TQueryTableProducer.<P>');
CustomerOrders.Header.Add(
'Orders for: ' + CustomerCompany.AsString);
Response.Content := CustomerOrders.Content;
end
else
Response.Content := Format(
'<html><body><b>Customer: %s not found</b></body></html>',
[Request.QueryFields.Values['CustNo']]);
finally
Customer.Close;
第17章 使用WebBroker 组件创建Web 服务器 449
图17.7 显示的Web 页面是由CGI 服务器程序生成的,该程序 存储了一个cookie ,用于标识用户的刷新或访问次数
procedure TWebModule1.RootHTMLTag(Sender: TObject; Tag: TTag; const TagString: String; TagParams: TStrings; var ReplaceText: String); begin
if( TagString = 'COUNT' ) then
ReplaceText := GetCountText( Request, Response ) else if( TagString = 'COOKIEDATA' ) then
ReplaceText := GetCookieText( Request, Response ); end;
如果遇到<#COUNT>标记,则调用GetCountText ;如果TagString 是<#COOKIEDATA>,则调用GetCookieText (参见图17.8的例子,在
cookie 文件中包含cookie 计数值)。

GetCookieText 的实现从TWebRequest.CookieFields 中读出所要求的cookie 的名字和值。

图17.8 cookie 相应的文本文件包含了cookie 的信息。

图中cookie 的当前计数值是高亮显示的
function TWebModule1.GetCookieText( Request : TWebRequest; Response : TWebResponse ) : String; begin
450 Delphi 6应用开发指南
result := 'Before increment:'+Request.CookieFields[0]; end;
GetCountText 向cookie 集合添加一个cookie ,分配cookie 和名字,在cookie 存在的情况下读出其值。

在把cookie 转换为整数再逆向转换时使用了异常处理块,以防在第一次访问时cookie 值未初始化的情况。

该cookie 在一天后过期,就不是安全的cookie ,而且只作为对任意域的响应发送,而且路径限制为/scripts/Cookie.exe/。

function TWebModule1.GetCountText( Request : TWebRequest;
Response : TWebResponse ) : String; begin
with Response.Cookies.Add do
begin
Name := 'Count';
Value := Request.CookieFields.Values['Count']; try
Value := IntToStr(StrToInt(Value) + 1); except
Value := '1'; end;
Secure := False;
Path := '/scripts/Cookies.exe/';
Expires := Now + 1; // this cookie expires in one day result := Value; end; end;
现在可以发现,Web 编程还是有许多事情要做的。

显然需要掌握HTML 编程,包括向Web 页面添加输入域和其他可视化控件。

请记住,在选择Web 内容时有几种可能性。

Web 服务器可以返回包含JavaScript 或VBScript 的ASP ,也可以是XML 、WML 。

每个协议都有其自身的语法和要求,但都可以创建内容丰富的Web 站点。

采用工具来方便文档的创建,和使用页面生成器的HTMLFile 特性,都是好主意。

使用工具可以减轻学习不同协议的负担,而HTMLFile 特性可以将外部的HTML 模板与页面生成器关联起来。

通过使用外部HTML 模板,可以修改Web 内容而无需重建Web 服务器程序。

17.4 小 结
本章对HTML 进行了综述。

超文本标记语言可以创建丰富的Web 页面,而无需多少真正的聪明。

对于创建Web 的内容来说,较好的起步策略是模仿您所喜欢的站点。

可以看到大多数Web 站点的源代码,并将其保存到本地计算机。

HTML。

相关文档
最新文档