6. Active Server Pages
本章主要介绍Active Server Pages,解释Active Server Pages指令之基本概念,并讨论较复杂的应用程式,例如,如何维持状态等。
本章不含下列资讯:
了解Active Server Pages
使用Active Server Pages(ASP)将能够容易的建立Web动态内容和建构功能强大的Web应用程式。不论您是Web设计者或Web开发者,这个简介将说明ASP如何对您有所帮助。
本节不包含下列资讯:
Active Server Pages简介
Microsoft Active Server Pages(ASP)是一种伺服器端的指令环境,可用来建立和执行动态的互动式Web伺服器应用程式。您可用ASP来结合HTML页面、指令命令和COM元件,以建立互动式Web网页或功能强大的Web应用程式。
对於HTML写作者
如果您是HTML写作者,将会发现利用ASP撰写的伺服器端指令,是开始建立更复杂的Web应用程式的简易方法。如果您曾经想将HTML表单资讯存入资料库中,亦或依照访客的喜好设定将Web站台个人化,或根据浏览器的不同而使用不同的HTML功能,您将会发现ASP提供了令人赞赏的解决方案。例如,若要在Web伺服器处理使用者输入,就必须学习类似Perl或C的语言,以建立传统的Common Gateway Interface(CGI)应用程式。不过如今您可用ASP 来收集HTML表单资讯,并使用直接内嵌於HTML文件中的简易伺服器端指令将它传送至资料库。若您已经熟悉指令语言,例如Microsoft VBScript或Microsoft JScript(JScript是Microsoft的ECMA 262语言规格),则学习ASP对您来说几乎没什麽困难。
若要立即开始使用ASP,请参阅线上产品文件中的〈ASP教学课程〉,然後返回这些主题来取得有关撰写伺服器端指令的详细资讯。
对於经验丰富的Web指令设计师
由於ASP与语言无关,若您熟练如VBScript、JScript或PERL的指令语言,就已经知道如何使用Active Server Pages。在您的ASP网页中,还可以在 COM相容的指令引擎上使用任何已经安装的指令语言。ASP附有VBScript和 JScript指令引擎,但您也可以安装协力厂商开发的PERL、REXX和Python等引擎。
对於Web开发者和程式设计师
若以程式设计语言来开发後端Web应用程式,例如Visual Basic、C++或 Java,就会发现利用ASP可以快速建立Web应用程式。除了新增指令来建立应用程式吸引人的HTML介面之外,还可以建构自己的COM元件。您可以将应用程式的工作逻辑压缩成可重覆使用的模组,然後藉由指令、其他元件或另一个程式来呼叫此模组。
Active Server Pages模式
当浏览器向Web伺服器要求 .asp档案时,就会开始执行伺服器端指令。然後Web伺服器会呼叫ASP由上而下来处理要求的档案、执行任何指令命令,以及传送Web网页至浏览器。
因为指令是在伺服器执行,而不是在用户端执行,因此Web伺服器负责执行建立传送至浏览器的HTML页面所需的所有工作。伺服器端指令无法立即复制,因为只有指令的结果会传回至浏览器。使用者并无法检视建立该页面的指令命令。
ASP的新增功能
新版的Active Server Pages(ASP)多增加了好几项新的功能,让指令设计者与Web应用程式开发者使用起来更为得心应手。
ASP中的重要变更
ASP已经历过几次重要的变更和强化。如果您是从旧版的ASP更新过来的,应该已经注意到这些变更。
说明
如果想知道ASP的新功能,请参阅〈ASP的新增功能〉一节。
建构ASP网页
ASP提供了强大且富弹性的架构,任何COM所接受的指令或程式语言,均可用来建立伺服器端的指令。本节所教导的是一个基本概念,即如何利用指令来建立一个 .asp档。从建立回圈到灵活运用资料库及处理异动,学习如何完成基本程式设计工作。无论您是指令初学者或高手,本章所讨论之内容皆可视为未来开发的指标与示范。希望藉此能鼓励各位运用更富巧思的方式来使用ASP,以 开发效能更高、更易维护的应用程式。
本节内容涉及到一些指令及程式设计概念,但这些均非本节所要教导的主要内容。Microsoft的指令语言(Microsoft VBScript及Microsoft JScript)提供了许多文件可供参考,而坊间书店亦可买到许多与指令相关的书籍。如果您对指令并不熟悉,那麽可利用这许多的书籍、课程及Internet资源,来协助您驾驭这些语言。
本节不含下列资讯:
建立ASP网页
Active Server Pages(ASP)档案为文字档,其副档名为 .asp,其中包含下列各项组合:
建立 .asp档案的快速方法是将现有的 .htm或 .html档案副档名更改为 .asp副档名。如果档案不包含任何ASP功能,则伺服器会省略ASP指令处理,并有效率地将档案传送至用户端。如此可提供Web开发者极大的弹性,因为即使稍後不计画新增ASP功能,也可以指定档案 .asp的副档名。
若要在Web发行 .asp档案,请将新档案存入Web站台的虚拟目录中(确定该目录已启用「指令」或「执行」权限),接着键入档案的URL,即可用浏览器来要求档案(请记住,浏览器必须支援ASP网页,因此无法以键入实际路径来要求 .asp档案)。在浏览器载入档案之後,会通知您伺服器已经传回HTML 页面。这起初看起来有点奇怪,但请记住,伺服器会在传送档案之前分析和执行 所有的ASP伺服器端指令,使用者便会收到标准的HTML。
您可以使用任何文字编辑器来建立 .asp档案。在进行时,可能会发现使用具有增强支援ASP的编辑器会更有成效,例如Microsoft Visual InterDev(若需其他资讯,请拜访Microsoft Visual InterDev Web站台 http://msdn.microsoft.com/vinterdev/ )。
新增伺服器端指令命令
伺服器端指令是用来连续发出指令至Web伺服器的一系列命令(如果您先前已开发过Web站台,您很可能已熟悉在Web浏览器执行的用户端指令)。在 .asp档案中,指令与文字和HTML的分隔符号有所差别。 分隔符号 是标示单元的开头或结束之字元或字元序列。在HTML中,这些分隔符号为小於(<)和大於(>)符号,用於括住HTML标记。
ASP使用分隔符号 <% 和 %> 来括住指令命令。您可以使用分隔符号来包含适用於指令语言的任何指令。下列范例显示简单的HTML页面,其中包含指令命令:
<HTML>
<BODY>
此页面上次重新整理的时间为 <%= Now()%>。
</BODY>
</HTML>
VBScript函数 Now ()会传回日期和时间。当Web伺服器处理这个页面时,会将 <%=Now()%> 以目前的日期和时间来取代,并以下列结果将页面传回浏览器:
此页面上次重新整理的时间为01/29/99 2:20:00 PM。
分隔符号括住的命令称为主要指令命令,必须藉由主要指令语言来处理。指令分隔符号中所用的任何命令必须适用於主要指令语言。在预设情况下,主要指令语言为VBScript,但您也可以设定不同的预设语言。请参阅本章稍後 〈使用指令语言〉 。
若您已经熟悉用户端指令,就知道HTML <SCRIPT> 标记可用来括住指令命令和运算式。每当需要在 .asp档案中以多种语言来定义程序时,您也可以在伺服器端指令使用<SCRIPT> 标记。若需其他资讯,请参阅本章稍後 〈使用指令语言〉 。
混合HTML和指令命令
您可以在ASP分隔符号中包含任何适用於主要指令语言的陈述式、运算式、程序或运算元。VBScript和其他指令语言中的陈述式在语句构造上是完整的单元,用以表达一种动作、宣告或定义。以下出现的条件式 If...Then...Else 陈述式为一般的VBScript陈述式:
<%
Dim dtmHour
dtmHour = Hour(Now())
If dtmHour < 12 Then
strGreeting = "Good Morning!"
Else
strGreeting = "Hello!"
End If
%>
<%= strGreeting %>
这个指令会根据时间来指定值 "Good Morning!" 或 "Hello!" 至字串变数strGreeting。<%=strGreeting %> 陈述式会将变数目前的值传送至浏览器。
因此,在中午12:00(在Web伺服器的时区)之前检视此指令的使用者会看到下列此行文字:
Good Morning!
在中午12:00之後检视此指令的使用者会看到下列文字:
Hello!
您可以在陈述式区段之间包含HTML文字。例如,下列指令在 If...Then...Else 陈述式中混合HTML,会与先前的指令范例得到相同的结果:
<%
Dim dtmHour
dtmHour = Hour(Now())
If dtmHour < 12 Then
%>
Good Morning!
<% Else %>
Hello!
<% End If %>
如果条件为真,亦即如果时间在中午之前,Web伺服器会传送条件式之後的HTML(Good Morning!)至浏览器;否则会传送Else之後的HTML(Hello!)至浏览器。这种混合HTML和指令命令的方式便於重叠数行HTML文字的 If...Then...Else 陈述式。若要在Web网页的许多地方显示招呼语,则第一个的范例比较有用。您可以只设定一次变数值,然後让它重覆显示。
与其使用指令命令来发布HTML文字,不如从指令命令中将HTML文字传回浏览器。若要将文字传回浏览器,请使用ASP内建物件 Response 。下列范例将与先前的指令得到相同的结果:
<% Dim dtmHour dtmHour = Hour(Now()) If dtmHour < 12 Then Response.Write "Good Morning!" Else Response.Write "Hello!" End If %>
Response.Write 会将它後面的文字传送至浏览器。当您要动态建构传送至浏览器的文字时,请在陈述式中使用 Response.Write 。例如,您可能要建立包含数个变数值的字串。您可在稍後 〈使用元件与物件〉 与 〈传送内容到浏览器〉 中学到更多有关 Response 物件和一般物件的资讯。现在您只要注意到有数种方法能将指令命令插入HTML页面中即可。
您可以在ASP分隔符号中包含使用预设主要指令语言撰写的程序。请参阅稍後之 〈使用指令语言〉 以获得其他资讯。
若您使用JScript指令,则可以直接在ASP指令中插入大括号,其中表示一句陈述式,甚至可以在其间发布HTML标记和文字。例如:
<%
if(screenresolution == "low")
{
%>
这是文字版本的页面。
<%
}
else
{
%>
这是多媒体版本的页面。
<% } %>
--或--
<%
if(screenresolution == "low")
{
Response.Write("这是文字版本的页面。")
}
else
{
Response.Write("这是多媒体版本的页面。")
}
%>
使用ASP语句
ASP提供了一种不属於您用的指令语言之一部分的语句:输出语句和处理语句。
ASP 输出语句 <%= expression %> 会显示运算式的值。此输出语句相当於使用 Response.Write 来显示资讯。例如,输出运算式 <%= city %> 会在浏览器显示文字Baltimore(目前的变数值)。
ASP 处理语句 <%@ keyword %> 可提供ASP处理 .asp档案所需的资讯。例如,下列语句会将VBScript设定为页面的主要指令语言:
<%@ LANGUAGE=VBScript %>
处理语句必须出现在 .asp档案的第一行。若要在页面上新增多个语句,这些语句必须在相同的分隔符号中。不要将处理语句放在包含 #Include 陈述式的档案中(若需其他资讯,请参阅稍後 〈包含档〉 )。您必须在符号(@)和关键字之间加入空格。处理语句具有下列关键字:
重要
您可以在单一语句中包含多个关键字。各个关键字/值对必须以空格隔开。请不要在等号(=)旁边加上空格。
下列范例设定指令语言和字码页:
<%@ LANGUAGE="JScript" CODEPAGE="932" %>
指令中的空白
如果主要指令语言为VBScript或Jscript,ASP会移除指令中的空白。对於其他指令语言,ASP会保留空白,以正确编译与位置或缩排相关的语言。空白包括空格、标签、换行符号和新行。
对於VBScript和Jscript,可以在开放分隔符号之後和封闭分隔符号之前使用空白,使指令容易阅读。下列所有陈述式都有效:
<% Color = "Green" %> <%Color="Green"%> <% Color = "Green" %>
ASP会移除陈述式的封闭分隔符号和後续陈述式的开放分隔符号之间的空白。不过,最好练习使用空格来增进可读性。若需要保留两个陈述式之间的空白,例如在句中显示变数值时,可以使用HTML不分段空格字元( )。例如:
<% '以字串值来定义两个变数。 strFirstName = "Jeff" strLastName = "Smith" %> <P>This Web page is customized for "<%= strFirstName %> <%= strLastName %>." </P>
使用指令语言
像Visual Basic、C++ 与Java这类以低阶方式来存取电脑资源的程式语言,可用来撰写复杂、高弹性的程式。而指令语言则是用来建立功能有限的小程式,我们称之为指令(script),它用来在Web伺服器或浏览器上执行Web站台的功能。指令语言并不像一般较复杂的程式,它是用解译器来解译的;即指令陈述式是经由一个称为「指令解译器」的中介程式来循序执行。虽然用解译器来执行比较费时,但指令语言较容易学习且提供了强大的功能。指令可内嵌在HTML 网页中作为内容的一部分,或用来组成COM元件将进阶的商业逻辑纳入其中。
因为Active Server Pages的关系,Web的开发者可运用各种不同的指令语言,来撰写在伺服器上执行的指令。事实上,在同一个 .asp档之中,可使用数种不同的指令语言。除此之外,由於指令是经由伺服器端读取及处理的,因此,要求 .asp档案的浏览器并不需要支援指令解译功能。
只要在Web伺服器上安装适当的指令引擎,就可以使用任何的指令语言。 指令引擎是一种程式,用来处理特殊语言所撰写的处理程序指令。Active Server Pages附有两种指令引擎:Microsoft Visual Basic Scripting Edition(VBScript)以 及Microsoft Jscript。您也可以安装并使用其他指令语言的引擎,如REXX、PERL 与Python。
如果您熟悉Visual Basic程式设计,应可立即上手使用VBScript,因为它是根据Visual Basic所发展出来的子系统。而如果您所熟知的是Java、C、或C++ 程式设计,那麽会发现JScript语法非常面熟,虽然Jscript和Java或C并没有直接的关系。
如果您对其他指令语系,如REXX、Perl、或Python较为熟悉,可安装适当语系的指令引擎,以便於使用该语言。Active Server Pages是COM指令的主机;如欲使用某种语言,则必须遵照COM Scripting标准来安装该语系之指令引擎,并以COM(元件物件模型)物件的方式常驻在Web站台。
设定主要指令语言
ASP主要指令语言是一种用来处理在 <% 与 %> 分隔符号间之指令的语言。预设的主要指令语言为VBScript。您可指定任何指令引擎的指令语言作为主要指令语言。在ASP应用程式中,您可逐页设定主要指令语言,或一次设定全部的页面。
设定应用程式的语言
如欲设定应用程式所有页面的指令语言,可在Internet Information Services 嵌入式管理单元中,在 应用程式选项 标签页中设定 预设 ASP语系 属性。若需其他资讯,请参阅第3章之
〈设定ASP应用程式〉 。
设定页面的语言
如欲为单一页面设定主要指令语言,请在 .asp档案起始处加上<%@ LANGUAGE %> 即可。其语法如下:
<%@ LANGUAGE= {ScriptingLanguage} %>
其中ScriptingLanguage指的就是您希望在该页使用的主要指令语言。该页面之设定会将原应用程式中所有页面之全域设定覆盖过去。
请依照指引来使用ASP指令;若需其他资讯,请参阅之前 〈建立ASP网页〉 。
说明
如果您使用的语言和主要指令语言有所出入,而不支援 Object.Method 语法,那麽一定要先建立 LanguageEngines 登录机码才行。若需其他资讯,请参阅《Microsoft Internet Information Services 5.0超级管理手册-网页开发篇》。
在伺服器上使用VBScript与JScript
在伺服器上的ASP使用VBScript时,有两个VBScript功能无法使用。因为以Active Server Pages所写的指令会在伺服器上执行,而伺服器并不支援这两个VBScript陈述式使用者介面元素: InputBox 与 MsgBox 。另外,请不要在伺服器端的指令中使用VBScript函数 CreateObject 及 GetObject 。请改用 Server.CreateObject ,以便ASP追踪物件例项。由 CreateObject 或 GetObject 建立之物件无法存取ASP 内建物件,且无法参与各项异动。这项规则只有在使用IIS Admin物件及Java 别名(moniker)时例外。若需其他资讯,请参阅第8章之 〈使用IIS Admin物件〉 及本章稍後的 〈从Java类别建立物件〉 。
若需所有VBScript与JScript之运算子、函数、陈述式、物件、属性及方法等之清单与描述,请参考VBScript Language Reference及JScript Language Reference。此参考资料可在Microsoft Windows Script Technologies Web网站中找到,网址在 http://msdn.microsoft.com/scripting/ 。
运用注解
因为所有ASP的指令均先经由伺服器端处理,所以不必因为浏览器不支援指令解译,而用HTML注解标记将指令隐藏起来。所有的ASP指令都必须经处理过後,内容才会传送到浏览器。您可使用HTML注解为HTML网页加上备注;使用者在查看HTML原始码时即可看见注解。
VBScript注解
VBScript使用的是上标点(')式的注解。和HTML注解不同的是,这些注解在指令处理过後,并不会送回给浏览器。
<% '本行及以下二行均为注解。 'PrintTable函数会印出 '阵列中的所有元素。 PrintTable MyArray() %>
在输出陈述式中不能含有注解。举例来说,第一行有效,第二行则无效,因为句首为 <%=。
<% i = i +1 '此陈述式递增i(本行指令有效)。%> <%= name '本行陈述式列印变数名称(本行指令无效)。%>
JScript注解
JScript以//作为注解字元。每行注解均须使用这些字元。
<% var x x = new Date() //本行将目前的日期传送给浏览器, //转译成字串。 Response.Write(x.toString()) %>
大小写之区分
VBScript不分大小写。举例来说,如欲引用ASP的 Request 物件,用 Request 或 request 均可。因为不分大小写,所以无法以大小写的方式来区分变数名称。比方说,用Color及color来建立两个不同的变数是不行的。
反之,JScript则区分大小写。在指令中使用JScript关键字时,每个字母都要和关键字参考页所显示的一模一样。例如,用 date 而不用 Date ,会造成错误的结果。本文件所显示的ASP内建物件可与 JScript指令一起使用。
使用变数和常数
变数是指一个在电脑记忆体内具有名称的储存位置,里面包含了资料,例如:一个数字或一个文字字串。储存在变数内的资料,称为变数值。变数可让您储存、撷取以及处理「值」,而名称则是方便您了解指令所处理的工作。
宣告及命名变数
请务必遵照指令语言之规则与指示来命名及宣告变数。虽然变数在使用前,不必先行宣告;不过,宣告变数是个好习惯,它可避免某些错误发生。宣告变数,就是告诉指令引擎,有某个具名变数存在可供指令引用。
VBScript
VBScript并未强制规定变数在使用前要先宣告,但若能在使用前先行宣告所有的变数,是个比较好的指令程式撰写习惯。在VBScript中宣告变数,可使用 Dim 、 Public 、或 Private 等陈述式。例如:
<% Dim UserName %>
在 .asp档案中,我们可使用VBScript的 Option Explicit 陈述式,来要求变数明确地以 Dim、Private、Public 、及 ReDim 等陈述式来宣告。Option Explicit陈述式必须出现在任何一个ASP指令之後,但在所有HTML文字或指令之前。这个陈述式只对以 VBScript撰写的ASP指令有效,在Jscript指令中并无效果。
<% Option Explicit %>
<HTML>
<%
Dim strUserName
Public lngAccountNumber
%>
若需有关上述指令的其他资讯,请参阅VBScript Language Reference,您 可在Microsoft Windows Script Technologies Web站台中找到,网址为
http://msdn.microsoft.com/scripting/ 。
JScript
虽然JScript通常并未规定变数在使用前要先宣告,但若能在使用前先行宣告所有的变数,是个比较好的指令程式撰写习惯。要宣告变数,请使用 var 陈述式。例如:
<% var UserName %>
一般来说,只有当您要使函数内的变数与用在函数外部的全域变数有所区别时,才会需要在Jscript中宣告变数。在这种状况下,若您没有区分这两种变数,JScript会认定您所引用的变数均为全域变数。若需有关 var 陈述式的其他资讯,请参阅JScript Language Reference。此参考资料可在Microsoft Windows Script Technologies Web网站中找到,网址在 http://msdn.microsoft.com/scripting/ 。
变数领域
变数的领域或存活期限,决定了哪些指令命令可供存取。在程序中宣告的变数,其领域为区域性的;每回该程序执行时,其变数随之建立而又销毁。程序外的指令是完全无法存取这些变数的。而程序外所宣告的变数具有全域性;即,所有ASP网页上的指令皆可存取并修改这些变数。
说明
将变数限制在程序领域中使用,可增加程式之效能。
宣告变数时,区域变数和全域变数的名称可以相同。修改任一种变数的值并不会影响另一变数的值。如果您没有宣告变数,很可能会因疏失而修改到全域变数。举例来说,下列指令虽然有两个变数名称Y,但传回的值仍为1:
<%
Option Explicit
Dim Y
Y = 1
SetLocalVariable
Response.Write Y
Sub SetLocalVariable
Dim Y
Y = 2
End Sub
%>
下列指令传回之值为2,因为程式中并未明确宣告变数。程序将Y设定为 2,而指令引擎却认为程序要修改的是全域变数:
<%
Option Explicit
Dim Y = 1
SetLocalVariable
Response.Write Y
Sub SetLocalVariable
Y = 2
End Sub
%>
为了避免类似问题,最好养成宣告所有变数的习惯。如果您在 .asp档中使用 #Include 陈述式,将其他档案包含进来时,宣告举动就更形重要了。虽然被包含进来的指令和原来的 .asp档并不相同,但却被视为 .asp档的一部分。除非我们很清楚的宣告所有变数,否则极易混淆主指令中的变数和被包含进来的指令中的变数名称。主程式所用的变数必须和程序有所区分。
赋予变数工作阶段领域或应用程式领域
全域变数只能在单一的 .asp档案中使用。如果希望某个变数在该页以外也可使用,就得赋予该变数一个工作阶段或应用程式领域。工作阶段领域之变数可供单一使用者在单一ASP应用程式的所有网页上使用。而应用程式领域之变数,则可供所有使用者在该应用程式的所有页面中使用。用工作阶段变数来储存某一使用者之资讯是个不错的方式,例如,储存该使用者之喜好、姓名或身份等。应用程式变数可用来储存与其相关之所有使用者资讯,例如,和某个应用有关之问候语或应用程式所需的通用值等。
ASP还提供了两个内建物件来储存变数,即: Session 物件与Application物件。
您也可以另外建立工作阶段领域或应用程式领域之物件例项。若需其他资讯,请参阅稍後 〈设定物件领域〉 。
工作阶段领域
如欲赋予某一变数工作阶段领域,可将其储存在 Session 物件中,并赋予一个值给物件中的具名项目。例如,下列指令会将两个新变数存入 Session 物件中:
<% Session("FirstName")= "Jeff" Session("LastName")= "Smith" %>
若欲撷取 Session 物件中的资讯,请用输出指令(<%=)或 Response.Write 来存取该具名项目的值。下面的例子即是用输出指令来显示Session("FirstName")的值:
Welcome <%= Session("FirstName")%>
您可以将使用者的喜好设定储存在 Session 物件中,然後存取 这些喜好设定以决定要传送给使用者的页面。例如,您可在应用程式的第一页让使用者指定纯文字内容,然後将这个选择套用至使用者在此应用程式中所拜访的所有後续页面上。
<%
strScreenResolution = Session("ScreenResolution")
If strScreenResolution = "Low" Then
%>
这是文字版本的页面。
<% Else %>
这是多媒体版本的页面。
<% End If %>
说明
一些经常被引用的工作阶段领域变数,最好能像上述的例子一样,指派成区域变数,藉以提高效能。
应用程式领域
如欲赋予某一变数应用程式领域,可将其储存在 Application 物件中,并赋予一个值给物件中的具名项目。例如,下列指令将一个特定应用程式的问候语储存在 Application 物件中:
<% Application("Greeting")= "Welcome to the Sales Department!" %>
如欲从 Application 物件中撷取资料,则可用ASP输出指令(<%=)或 Response.Write ,从应用程式中的任一页面中存取具名项目的值。下面例子便是使用输出指令来显示Application ("Greeting")的值:
<%= Application("Greeting")%>
同样地,如果指令中反覆引用到应用程式领域变数,最好将它改成区域变数,以增进效能。
使用常数
所谓 常数 ,是指替代一个数值或字串的名称。ASP提供了一些基本元件,如ActiveX资料物件(ADO),来定义一些在指令中可使用的常数。元件可在 元件类型程式库 中宣告常数,其中包括COM所支援的物件及类型。只要在 .asp档内宣告一个类型程式库,该 .asp档中的任何指令皆可使用这些定义过的常数。同理,在Global.asa档中亦可宣告一类型程式库,任何该应用程式的 .asp档均可引用这些常数。
如欲宣告类型程式库,可在 .asp档或Global.asa档中以<METADATA> 标记来定义。举例说明,要宣告ADO类型程式库,可使用下列陈述式:
<!--METADATA NAME="Microsoft ActiveX Data Objects 2.5 Library"
TYPE="TypeLib" UUID="{00000205-0000-0010-8000-00AA006D2EA4}"-->
如果不想用程式库的通用唯一识别元UUID,也可使用档案路径来引用类型程式库:
<!-- METADATA TYPE="typelib" FILE="c:\program files\common files\system\ado\msado15.dll"-->
您可在宣告类型资料库的 .asp档案使用ADO常数,或在应用程式中的 .asp档中使用,而该应用程式应有Global.asa包含在内,并宣告为ADO类型程式库。在下面例子当中,adOpenKeyset与adLock Optimistic都是ADO常数:
<% '建立并开启Recordset物件。 Set rstCustomerList = Server.CreateObject("ADODB.Recordset") rstCustomerList.ActiveConnection = cnnPubs rstCustomerList.CursorType = adOpenKeyset rstCustomerList.LockType = adLockOptimistic %>
下表列出一般常用之类型程式库及UUID:
| 类型程式库 | UUID |
|---|---|
| Microsoft ActiveX Data Objects 2.5 Library | {00000205-0000-0010-8000-00AA006D2EA4} |
| Microsoft CDO 1.2 Library for Windows 2000 Server | {0E064ADD-9D99-11D0-ABE5-00AA0064D470} |
| MSWC Advertisement Rotator Object Library | {090ACFA1-1580-11D1-8AC0-00C0F00910F9} |
| MSWC IIS Log Object Library | {B758F2F9-A3D6-11D1-8B9C-080009DCC2FA} |
有关<METADATA>标记的其他资讯,请参阅《Microsoft Internet Information Services 5.0超级管理手册-网页开发篇》。
在ASP先前的版本中,有些元件是在档案中定义常数,而使用这些常数的每个ASP档,均须将这些定义档案包含进来。利用 #Include 将常数定义包含进来的语法现在仍可使用,但一般说来,类型程式库比较好用,指令也较容易升级。在未来的ASP版本中,元件可能不再提供常数定义档了。
说明
相较於 #Include ,使用 <METADATA>标记较能增加Web应用程式之效能。
您也可以定义自己的常数。在VBScript里,可使用 Const 陈述来定义。而在Jscript里,您可用 var 陈述将常数指派给变数。如果有些常数经常为不同的 .asp档案所使用,您可将定义放在另一个档案内,每次 .asp档欲使用常数时,就将定义档包括进来。
与用户端指令互动
利用ASP产生或处理用户端指令,可以扩充其效果。例如,您可以编写用户端指令,根据伺服器特有的变数、使用者的浏览器类型、或者HTTP要求参数,将用户端指令组合起来。
将用户端指令陈述式摆在用户端指令中(用HTML<SCRIPT>标签括起来),如底下的范例范本所示,可以在接到要求时,动态地起始和变更用户端指令:
<SCRIPT LANGUAGE="VBScript"> <!-- 变数 = <%=伺服器定义的值 %> . . . 用户端指令 <% 用来产生用户端陈述式的伺服器端指令 %> 用户端指令 . . . --> </SCRIPT>
纳入这种功能可以产生一些有用而且很有意思的应用程式。例如,底下便是一个简单的用户端指令(以VBScript编写),可以处理用户端的指令(以Jscript 编写):
<%
Dim dtmTime, strServerName, strServerSoftware, intGreeting
dtmTime = Time()
strServerName = Request.ServerVariables("SERVER_NAME")
strServerSoftware = Request.ServerVariables("SERVER_SOFTWARE")
'产生一个乱数。
Randomize
intGreeting = int(rnd * 3)
%>
<SCRIPT LANGUAGE="JScript">
<!--
//呼叫函数以显示欢迎讯息
showIntroMsg()
function showIntroMsg()
{
switch(<%= intGreeting %>)
{
case 0:
msg = "This is the <%= strServerName%> Web server
running <%= strServerSoftware %>."
break
case 1:
msg = "Welcome to the <%= strServerName%> Web
server. The local time is <%= dtmTime %>."
break
case 2:
msg = "This server is running <%= strServerSoftware %>."
break
}
document.write(msg)
}
-->
</SCRIPT>
这种指令可以扩充,例如扩充以便设定用户端资料库或者DHTML的个人化指令。有创意的运用这种技巧,也可以减少重覆执行的情形和伺服器的处理工作。
撰写程序
所谓 程序 乃一组指令命令,用来执行某项工作并传回一个值。您可以定义自己的程序,并在指令中反覆呼叫使用。
程序定义可放在呼叫程序的同一个 .asp档内;或者,您也可以将经常使用的程序放在一个共用的 .asp档案内,要在其他的 .asp档案中呼叫这些程序时,可使用 #Include 来引用它。当然,您也可以将功能浓缩在一个 COM元件之中。
定义程序
程序定义可放在 <SCRIPT> 和 </SCRIPT> 标记之间,且必须遵循指令语言的宣告原则。如果用的不是主要指令语言,则使用 <SCRIPT> 元素来定义程序。但是,要以指令分隔符号(<%及%>)来定义主要指令语言中的程序。
在您使用HTML的 <SCRIPT> 标记时,一定要用两个属性,以确保伺服器端会处理这个指令。使用 <SCRIPT> 标记的语法如下:
<SCRIPT LANGUAGE=JScript RUNAT=SERVER>
程序定义
</SCRIPT>
RUNAT=SERVER属性会告诉Web伺服器要在伺服器上处理这个指令。如果没有设定这个属性,指令就会由用户端的浏览器来处理。LANGUAGE属性则决定了该程式所使用的指令语言为何。只要伺服器上有安装指令引擎,就可以指定使用该语言。若要指定VBScript语言,请使用VBScript这个值;若要指定 Jscript语言,则必须使用Jscript这个值。如果您没有设定LANGUAGE属性,则该段指令将会以主要指令语言来直译。
在指令区块中的命令,必须使用所选择的指令语言,来形成一个或多个完整的程序。例如,下列的指令定义了JScript程序 MyFunction 。
<HTML>
<SCRIPT LANGUAGE=JScript RUNAT=SERVER >
function MyFunction()
{
Response.Write("You called MyFunction().")
}
</SCRIPT>
重要
伺服器端的 <SCRIPT> 标记内,不要放进任何不属於该程序的指令命令。任何不属於程序内的指令,会造成许多未知的结果,因为这些指令的执行是不按理出牌的。另外,在程序内不可使用ASP输出命令 <%= %>。应使用Response.Write将内容送至浏览器。
呼叫程序
呼叫程序时,必须将程序名称包含到指令中来。如果您是从VBScript中呼叫JScript程序,在程序名称後面必须加上括弧;如果程序没有引数,请使用空的括弧。如果您是从JScript呼叫VBScript或JScript程序,请在程序名称後面一定要附上括弧。
在VBScript里,您也可以用 Call 这个关键字来呼叫程序。但是,被呼叫的程序如果要求引数,则引数必须列在括弧之内。如果您省略关键字 Call ,那麽包围引数的括弧也必须一同省略。如果您用 Call 这个语法来呼叫任何内建或使用者定义之函数,则传回的值会被丢弃。
下面的例子用两种不同的指令语言(VBScript及Jscript)来建立和呼叫程序。
<%@ LANGUAGE=VBScript %>
<HTML>
<BODY>
<% Echo %>
<BR>
<% printDate()%>
</BODY>
</HTML>
<%
Sub Echo
Response.Write "<TABLE>" & _
"<TR><TH>Name</TH><TH>Value</TH></TR>"
Set objQueryString = Request.QueryString
For Each strSelection In objQueryString
Response.Write "<TR><TD>" & p & "</TD><TD>" & _
FormValues(strSelection)& "</TD></TR>"
Next
Response.Write "</TABLE>"
End Sub
%>
<SCRIPT LANGUAGE=JScript RUNAT=SERVER>
function printDate()
{
var x
x = new Date()
Response.Write(x.toString())
}
</SCRIPT>
说明
VBScript呼叫JScript函数时,并不会区分大小写。
传递阵列给程序
在VBScript中,如欲传递整个阵列给程序,阵列名称後面应使用空的圆型括弧(小括号);在JScript中,则使用空的方型括号(中括号)。
集合的使用方法
大部分ASP内建的物件都有提供集合。 集合 是类似阵列的资料结构,可以用来储存字串、数字、物件以及其他的值。跟阵列不同的是,集合会随着项目被撷取或储存而自动扩张和收缩。项目的位置也会因为集合被修改而移动。要存取集合中的一个项目时,可以利用其独特的字串识别码、它在集合中的索引(位置)、或者反覆运算集合中的所有项目。
利用名称或索引存取一个项目
您可以参照物件独有的字串识别码或名称,以存取集合中的特定项目。例如, Contents 集合保存着储存於 Session 物件中的任何变数,还可以保存任何用以呼叫 Server.CreateObject 进行例项处理的物件。假定您已经将下列使用者资讯储存於 Session 物件中:
<% Session.Contents("FirstName")= "Meng" Session.Contents("LastName")= "Phua" Session.Contents("Age")= 29 %>
您可以利用字串识别码存取一个项目。您在将这个识别码储存於集合中时,已经建立起它与项目的关联。例如,下列运算式会传回字串 "Meng":
<%= Session.Contents("FirstName")%>
您也可以利用与项目关联的索引或编号来存取项目。例如,下列运算式可以撷取储存於 Session 物件第二个位置中的资讯,并传回 "Phua":
<%= Session.Contents(2)%>
ASP集合是从1开始编号的。随着项目的加入或移出集合,与某个项目相关的索引可能会改变,所以可别以为项目的索引是固定不变的而以之为依据。索引存取通常用来反覆运算集合(如下列主题中的描述),或者是用来存取唯读集合中的项目。
您也可以利用速记符号以名称来存取项目。ASP会以特定的顺序搜寻与物件有关联的集合。如果采用特定名称的项目只在物件的集合中出现一次,您可以不用集合的名称(虽然这样做可能会影响到性能):
<%= Session("FirstName")%>
存取储存於 Application 或 Session 物件中的项目时,不用集合名称通常都不会造成问题。不过,就 Request 物件来说,指定集合的名称会比较安全些,因为集合很可能包含具有重覆名称的项目。
反覆运算一个集合
您可以反覆运算集合中的所有项目,看看集合中储存哪些项目,或者是修改这些项目。要反覆运算集合时,必须提供集合的名称。例如,您可以用VBScript 的 For...Each 陈述式来存取您储存在 Session 物件中的项目:
<% '宣告一个计数器变数。 Dim strItem '对於集合中的每一个项目,显示其值。 For Each strItem In Session.Contents Response.Write Session.Contents(strItem)& "<BR>" Next %>
您也可以利用VBScript的 For...Next 陈述式反覆运算一个集合。例如,如果要列出储存於上一个例子中的 Session 里的叁个项目,可以使用下列陈述式:
<% '宣告一个计数器变数。 Dim intItem '重覆执行回圈,直到计数器的值等於3。 For intItem = 1 To 3 Response.Write Session.Contents(intItem)& "<BR>" Next %>
通常您并不知道储存於集合中的项目有多少个,因此ASP支援集合的 Count属性,可以传回集合中项目的数目。您必须用 Count 属性来指定计数器的终止值。
<% '宣告一个计数器变数。 Dim lngItem, lngCount lngCount = Session.Contents.Count '重覆执行回圈,直到计数器的数目等於集合中 '项目的数目。 For lngItem = 1 To lngCount Response.Write Session.Contents(lngItem)& "<BR>" Next %>
在JScript中,您必须用 for 陈述式对整个集合进行回圈处理。将 Count 属性用在Jscript for 陈述式中时,为了更有效率,应该将 Count 的值指定给区域变数,并用该变数来设定计数器的终止值。如此指令引擎就不必每次都要到整个回圈中去找 Count 的值。以下的范例示范的便是这种技巧:
<%
var intItem, intNumItems;
intNumItems = Session.Contents.Count;
for(intItem = 1; intItem <= intNumItems; intItem++)
{
Response.Write(Session.Contents(intItem)+ "<BR>")
}
%>
MicrosoftJScript支援 Enumerator 物件,也可以用来反覆计算 ASP集合。 atEnd 方法可以指出集合中是否还有其他项目。 moveNext 方法则可以移至集合中的下一个项目。
<%
Session.Contents("Name")= "Suki White"
Session.Contents("Department")= "Hardware"
.
.
.
//建立一个Enumerator物件。
var mycollection = new Enumerator(Session.Contents);
/反覆计算集合并显示各个项目。
while(!mycollection.atEnd())
{
var x = myCollection.item();
Response.Write(Session.Contents(x)+ "<BR>");
myCollection.moveNext();
}
%>
用子识别码(Subkey)反覆计算集合
指令可能将几个相关的值内嵌於一个cookie中,以减少浏览器和Web伺服器之间传送的cookie数目。因此 Request 和 Response 物件的 Cookies 集合可以在一个项目中保存多个数值。这些子项目(或者说子识别码)可以个别存取。只有 Request.Cookies 和 Response.Cookies 集合支援子识别码。 Request.Cookies 只支援读取操作, Response.Cookies 只支援写入操作。
以下的范例会建立一个一般的cookie和一个有子识别码的cookie:
<% '传送一个cookie到浏览器。 Response.Cookies("Fruit")= "Pineapple" '传送一个有子识别码的cookie到浏览器。 Response.Cookies("Mammals")("Elephant")= "African" Response.Cookies("Mammals")("Dolphin")= "Bottlenosed" %>
送给浏览器的HTTP回应中的cookie文字如下所示:
HTTP_COOKIE= Mammals=ELEPHANT=African&DOLPHIN=Bottlenosed; Fruit=Pineapple;
您也可以重覆执行 Request.Cookies 集合中的所有cookie以及cookie中的所有子识别码。不过,反覆计算没有子识别码的cookie中的子识别码并不会产生一个项目。您可以先检查一下cookie是否有子识别码,以避免这种情况,方法是使用 Cookies 集合的 HasKeys 属性。以下的范例示范的便是这种技巧。
<% '宣告计数器变数。 Dim Cookie, Subkey '显示整个cookie集合。 For Each Cookie In Request.Cookies Response.Write Cookie If Request.Cookies(Cookie).HasKeys Then Response.Write "<BR>" '显示子识别码。 For Each Subkey In Request.Cookies(Cookie) Response.Write " ->" & Subkey & " = " & Request. Cookies (Cookie)(Subkey)& "<BR>" Next Else Response.Write " = " & Request.Cookies(Cookie)& "<BR>" End If Next %>
这个指令会传回下列结果:
Mammals ->ELEPHANT = African ->DOLPHIN = Bottlenosed Fruit = Pineapple
识别码名称的大小写
Cookies、Request、Response 以及 ClientCertificate 集合可以参照同一个唯一的字串识别码名称。例如,以下的陈述式参照相同的识别码名称User,但是会为各个集合传回不同的值:
strUserID = Request.Cookies("User") strUserName = Request.QueryString("User")
识别码名称的大小写是由指定值给识别码的第一个集合设定的。请仔细研究一下底下这个指令:
<% '使用UserID识别码,从QueryString集合撷取一个值。 strUser = Request.QueryString("UserID") '参照拼法不同的识别码、UserId,传送一个cookie到浏览器。 Response.Cookies("UserId")= "1111-2222" Response.Cookies("UserId").Expires="December 31, 2000" %>
看起来被指定给cookie的识别码名称好像是UserId,事实上却是UserID (大写的字母不同)被指定给cookie。 QueryString 是第一个定义这个识别码的大小写之集合。
对集合数值的参照不受识别码名称大小写的影响,因此,除非您的应用程式对於识别码名称的处理要分大小写,否则这项行为不会影响您的指令。
反覆计算物件的集合
Session 和 Application 集合能够保存数量变数或物件例项。 Contents 集合则可以呼叫 Server.CreateObject 以保存数量变数和物件例项。 StaticObjects 集合可以保存在 Session 物件领域内用 HTML <OBJECT> 标记建立的物件。若需有关用这种方式为物件建立例项的其他资讯,请参阅稍後
〈设定物件领域〉 部分。反覆计算含有物件的集合时,可以存取物件的Session或Application状态资讯,或者存取物件的方法或属性。例如,假定您的应用程式用好几个物件建立一个使用者帐号,而且各个物件都有一个初始化方法。您便可以反覆计算 StaticObjects 集合以撷取物件属性:
<%
For Each Object in Session.StaticObjects
Response.Write Object & ": " & Session.StaticObjects
(Object)
Next
%>
ASP集合有何不同?
本文中描述的ASP集合类似Visual Basic的 Collection 物件,不过还是有一些不同之处。ASP集合支援 Count 内容和 Item、Remove 以及 RemoveAll 方法。它们不支援 Add 方法。
处理使用者输入
利用ASP的 Request 物件,我们可以建立出简单但功能强大的指令,用来收集与处理使用者在HTML表单中输入的资料。本节不仅告诉您如何设计基本的表单处理指令,也会教您从伺服器端以及使用者浏览器端检查表单输入资料是否正确的技巧。
关於HTML表单
HTML表单是最常用来收集Web资讯的方法,它包含许多种特殊的HTML 标记,是组成网页上使用者介面的元素。例如文字方块、按钮以及核取方块等等,都是表单网页中的一部分,让使用者能与Web网页互动,并将输入的资料传给 Web伺服器处理。
举例来说,以下这些HTML标记便组成了一个可以让使用者输入其姓氏、名字与年龄的表单,其中还含有一个按钮,使用者只要按下这个按钮,就可以把填好的资料传回Web伺服器。此表单中另外还有一个隐藏的输入标记(浏览器不会把这种标记显示出来),可将额外的资讯传给Web伺服器。
<FORM METHOD="Post" ACTION="Profile.asp"> <INPUT TYPE="Text" NAME="FirstName"> <INPUT TYPE="Text" NAME="LastName"> <INPUT TYPE="Text" NAME="Age"> <INPUT TYPE="Hidden" NAME="UserStatus" VALUE="New"> <INPUT TYPE="Sub7mit" VALUE="Enter"> </FORM>
详细解说HTML表单的所有标记并不在本文的范围之内,不过很多地方都有这类资讯,可以让您学习如何设计有用且引人注意的HMLT表单。例如,用Web浏览器的检视原始文件功能,就可以看到其他Web网站上建立的HTML 表单。此外,您也可以到Microsoft的MSDN Online网站
http://msdn.microsoft.com/ 来学习各种创新的HTML使用方法以及其他Internet技术等等。
使用ASP来处理表单输入的资料
HTML表单建立之後,接着就要开始处理使用者输入的资料,也就是把使用者输入的资料传给一个 .asp档案进行解析与处理。请您再仔细看看先前那个 HTML的例子。其中 <FORM> 标记的ACTION属性参考到一个称为 Profile.ASP的档案。当使用者表示要传送HTML资讯时,浏览器会用POST方法将资料传给此伺服器上的一个 .asp档案,也就是Profile.asp。这个 .asp档案中含有指令,可以处理收到的资料,并与其他指令、COM元件或资源(如资料库)互动。
使用ASP收集HTML表单传来的资讯,共有以下叁种基本方法:
前两种方法的运作模式基本上都是一样的,都是用表单与其他Web伺服器程式(ASP除外)互动,因此可大幅简化表单资料的收集与处理动作。第叁种方法也相当有用,将在稍後的〈检验表单的输入资料〉一节中示范。
取得表单输入的资料
ASP的 Request 物件提供两种集合,均可用来撷取以URL要求格式传送的表单资讯。
QueryString集合
QueryString 集合可以撷取传送给Web伺服器的表单资料,这些资料紧跟在URL後面,并以一个问号与URL隔开。表单资料可以用HTTP 的GET方法附在URL後面,也可以用手动的方式将表单资料附在URL之後。
举例来说,如果之前的表单范例采用GET方法 (METHOD= "GET"),当使用者输入的资料分别为Clair、Hector以及30时,伺服器将会收到以下这个URL要求:
http://Workshop1/Painting/Profile.asp?FirstName=Clair& LastName=Hector&Age=30&UserStatus=New
Profile.ASP中可能含有以下的表单处理指令:
Hello <%= Request.QueryString("FirstName")%>?lt;%= Request.
QueryString("LastName")%>.
You are <%= Request.QueryString("Age")%> years old!
<%
If Request.QueryString("UserStatus")= "New" Then
Response.Write "This is your first visit to this Web site!"
End if
%>
以上例子中,Web伺服器会传回以下的文字到使用者的浏览器:
Hello Clair Hector. You are 30 years old! This is your first visit
to this Web site!
QueryString 集合还有一个选择性的参数,可以用来存取(用 GET方法发出的)URL要求中的任何一个数值。您也可以用 Count 属性来计算某一种类型值的出现次数。
例如表单中若含有一个清单方块,其中列出好几个项目时,此表单便会产生以下这种要求:
http://OrganicFoods/list.asp?Food=Apples&Food= Olives&Food=Bread
您可以用以下这个指令计算多个值:
Request.QueryString("Food").Count
若要显示好几个值的类型,可以在List.ASP中加入以下指令:
<%
lngTotal = Request.QueryString("Food").Count
For i = 1 To lngTotal
Response.Write Request.QueryString("Food")(i)&
"<BR>"
Next
%>
以上指令的输出结果如下:
Apples Olives Bread
您也可以用以下的指令将所有的值显示成字串,并以逗号隔开:
<% Response.Write Request.QueryString("Item")%>
输出结果如下:
Apples, Olives, Bread
Form集合
用HTTP的GET方法将一串很长的复杂表单的值传给Web伺服器时,有可能会遇到资料丢失的情形。因为有些Web伺服器会限制URL查询字串的最大长度,当GET方法传递的表单值总长度超过上限时,其过长的部分就会被截断。如果您真的需要从表单中传送一大堆资料给Web伺服器,应该改用HTTP的 POST方法。将表单的资料放在HTTP要求的本文中传送,此种方法可传送的资料长度几乎没有任何限制。利用ASP Request 物件的 Form 集合,可撷取用POST方法传送的值。
Form 集合存放值的方法与 QueryString 集合类似。举例来说,当使用者在表单内输入一长串的名称之後,您就可以用以下的指令把这些名字全部撷取出来:
<% lngTotal = Request.Form("Food").Count For i = 1 To lngTotal Response.Write Request.Form("Food")(i)& "<BR>" Next %>
检验表单的输入资料
一个设计良好的表单,通常会含有一个用户端指令,负责检验使用者输入的资料是否正确,如果正确才将其传给伺服器。检验指令可以检查的范围包括:使用者输入的数字是否合乎规定、某个文字方块是否是空的等等。假设您的Web 网站含有一个可以让使用者计算投资报酬率的表单。那麽您大概会希望在浏览器把不知道是否正确的资料传给您的伺服器之前,先用程式检查使用者是否真的在适当的表单栏位中分别填入正确的数字或文字资料。
一般而言,这种检查的动作最好尽量在用户端进行比较恰当。在用户端进行检查,除了能更快提醒使用者输入错误之外,也可以做到较快速的反应、降低伺服器负荷量、以及省下网路频宽给其他软体使用。
以下这个用户端指令会在浏览器把资料传给伺服器之前,先对使用者输入的资料进行一番检查,看看使用者输入的帐户号码是不是全部由数字组成:
<SCRIPT LANGUAGE="JScript">
function CheckNumber()
{
if(isNumeric(document.UserForm.AcctNo.value))
return true
else
{
alert("Please enter a valid account number.")
return false
}
}
//此函数检查表单内的数值是否全部由数字组成。
//备注:要判断一个数值是否全部由数字组成,可利用JScript的isNaN方法
//应该是比较好的方式。但是,某些比较旧的浏览器并不支援这种方法。
function isNumeric(str)
{
for(var i=0; i < str.length; i++)
{
var ch = str.substring(i, i+1)
if( ch < "0" || ch>"9" || str.length == null)
{
return false
}
}
return true
}
</SCRIPT>
<FORM METHOD="Get" ACTION="balance.asp" NAME="UserForm"
ONSUBMIT="return CheckNumber()">
<INPUT TYPE="Text" NAME="AcctNo">
<INPUT TYPE="Submit" VALUE="Submit">
</FORM>
如果检查表单时必须存取资料库内的资料,则应该改用伺服器端的表单检查方式。在伺服器端进行检查,有一项很特殊的优点,就是能建立一个把资料传回给自己的表单。也就是说,.ASP档案本身就含有撷取使用者输入资料的HTML 表单(记住,ASP可以用来与用户端的指令以及HTML互动。若需其他资讯,请参阅之前 〈与用户端指令互动〉 部分)。使用者输入的资料会传回给同一个档案,由此档案负责检查资料的正确性,万一资料不正确时,亦需警告使用者。
利用这种方法处理以及检查使用者输入的资料,可以大幅强化Web表单的可用性与反应能力。例如,将错误资讯标示在表单内使用者输入错误资料的旁边,就能让使用者更容易找出错误的地方(一般而言,Web表单会用另一个Web 网页显示错误相关资讯。
举例来说,以下这个指令将资料传回给自己(Verify.asp),并呼叫一个自订的资料库查询函数,藉以检查使用者输入的帐户号码是否正确:
<%
strAcct = Request.Form("Account")
If Not AccountValid(strAcct)Then
ErrMsg = "<FONT COLOR=Red>Sorry, you may have entered an in-
valid account number.</FONT>"
Else
处理使用者输入的资料
.
.
.
Server.Transfer("Complete.asp")
End If
Function AccountValid(strAcct)
这里含有一个连接资料库的指令或是元件方法呼叫。
End Function
%>
<FORM METHOD="Post" ACTION="Verify.asp">
Account Number: <INPUT TYPE="Text" NAME="Account"> <%= ErrMsg %>
<BR>
<INPUT TYPE="Submit">
</FORM>
在以上例子中,此指令放在Verify.ASP这个档案里面,其中也含有一个 HTML表单。此档案将表单的ACTION属性指定为Verify.asp,所以可以把资料收回来给自己处理。
重要
如果您使用JScript在伺服器端进行资料检验,当您将 Request 集合项目( QueryString 或 Form )设定给区域变数时,请务必记得在集合项目後面加上一对空的小括弧。如果没有加上括弧,集合传回的就不会是字串而是物件。以下指令片段示范在JScript内如何正确地设定变数:
<%
var Name = Request.Form("Name")();
var Password = Request.Form("Password")();
if(Name > "")
{
if(Name == Password)
Response.Write("Your name and password are the
same.")
else
Response.Write("Your name and password are different.");
}
%>
如果集合含有多个以逗号隔开或可用索引存取的值时,VBScript的状况也是一样。换句话说,使用VBScript和JScript时,除了要在 Request 集合项目後面加上一对空的小括弧之外,也要指定欲存取之值的索引。例如以下这一行JScript程式就只会传回表单元件多个值中的第一个而已:
var Name = Request.Form("Name")(1);
使用元件与物件
COM元件是建立强大而实用的Web应用程式的关键。元件可以提供功能让您用在指令中执行专门化的工作,例如,执行金融交易或者验证资料。ASP 还提供一套基本元件,可以让您用来大幅强化指令的功能。
关於元件
COM元件是可以再使用、可程式化的建构区块,里面有执行一项工作或者一组工作所需的程式码。元件可以跟其他元件组合(甚至跨越网路)以建立一个Web应用程式。COM元件可以执行一般性的工作,所以您不必自行建立程式码来执行这些工作。例如,您可以利用股市跑马灯元件将最新的股票行情显示在 Web网页上。要建立能提供这种功能的指令是很困难的,而且,指令不能像元件那样重覆使用。
如果您是编写指令的新手,便可以编写采用元件的指令,而不必对元件的运作方式有任何认识。ASP附有您可以立即使用的基本元件。例如,您可以用「ActiveX资料物件」(ADO)元件来新增资料库到您Web网页的连接,或是从协力厂商开发者处取得其他元件。
如果您是个Web应用程式开发者,元件是将您的企业逻辑纳入可以重覆使用、而且安全的模组中的最佳选择。例如,您可以从一个处理销售订单的指令呼叫这个元件,用一个元件来验证信用卡号码。验证独立於订单的处理作业之外,因此您可以在信用卡验证处理变更时更新元件,而不必变更您的订单处理作业。此外,由於COM元件可以重覆使用,所以您可以将元件再用於其他指令和应用程式中。一旦将元件安装在您的Web伺服器之後,便可以从一个ASP伺服器端指令、ISAPI扩充功能、伺服器上的另一个元件、或者以其他与COM相容的语言编写的程式呼叫这个元件。
您可以用支援「元件物件模型」(COM)的任何程式语言,例如C、C++、 Java、Visual Basic或者各种指令语言来建立元件(如果您熟悉COM程式设计,就知道COM元件也称为「自动化」伺服器)。如果要在Web伺服器上执行,您 的COM元件就不能有任何图形化使用者介面元素,例如Visual Basic的 MsgBox 函数。图形化介面元素只能在伺服器上检视,而不能在浏览器上检视。
建立一个元件物件的例项
元件是动态连结程式库(.dll)或者可执行(.exe)档中的可执行程式码。元件提供一或多个 物件 ,它是自成一体的程式码,可以在元件中执行特定的功能。每一个物件都有方法(程式化的程序)和属性(行为特性)。如果要使用元件所提供的物件,就要建立一个物件的例项,并指定一个变数名称给新的例项。请使用ASP的 Server . CreateObject 方法或者HTML<OBJECT> 标签来建立物件例项。而用您的指令编写语言的变数指定陈述式给物件例项一个名称。建立物件例项时,必须提供其登录名称(PROGID)。至於ASP所提供的基本元件,您可以从参考页面取得物件的 PROGID(请参阅《Microsoft Internet Information Services 5.0超级管理手册-网页开发篇》。
例如,Ad Rotator元件会随机轮换一系列图形广告。Ad Rotator元件提供的一个物件叫做 Ad Rotator 物件,其PROGID为 MSWC.AdRotator 。如果要建立 Ad Rotator 物件的一个例项,可以采用下列陈述式中的一种:
VBScript :
<% Set MyAds = Server.CreateObject("MSWC.AdRotator")%>
Jscript :
<% var MyAds = Server.CreateObject("MSWC.AdRotator")%>
如果您已经熟悉VBScript或JScript,请记得不要用指令语言函数建立新的物件例项(VBScript中的 CreateObject 或者JScript中的 New )。您必须用ASP的 Server.CreateObject 方法,否则ASP将无法追踪您在指令中使用的物件。
您也可以用HTML<OBJECT>标签建立一个物件例项。您必须提供有 Server值的RUNAT属性,而且必须提供被设定给要用在指令中之变数名称的ID 属性。您可以利用登录名称(PROGID)或者登录编号(CLSID)来指出物件。以下的范例利用登录名称(PROGID)建立 Ad Rotator 物件的一个例项:
<OBJECT RUNAT=Server ID=MyAds PROGID="MSWC.AdRotator"></OBJECT>
底下的范例利用登录编号(CLSID)建立 Ad Rotator 物件的一个例项:
<OBJECT RUNAT=SERVER ID=MyAds CLASSID="Clsid:1621F7C0-60AC-11CF-9427-444553540000"></OBJECT>
以编写指令的方式建立COM元件
ASP支援Windows指令元件(Windows Script Component),这个强大的 Microsoft指令编写技术,可以让您用来建立COM元件。说得更明白一点就是, 您可以将常用的指令,例如,那些用来进行资料库存取或者产生内容的指令,纳入可以从 .asp档案或程式存取的可重覆使用的元件中。您可以用VBScript或者 JScript之类的语言编写指令,以建立Windows指令元件,而不需要特殊的开发工具。您也可以将Windows指令元件纳入以COM程式语言如Visual Basic、C++、或者Java编写的程式中。
以下便是一个用VBScript编写的Windows指令元件的范例,定义用来转换摄氏和华氏度数的方法:
<SCRIPTLET>
<Registration
Description="ConvertTemp"
ProgID="ConvertTemp.Scriptlet"
Version="1.00"
>
</Registration>
<implements id=Automation type=Automation>
<method name=Celsius>
<PARAMETER name=F/>
</method>
<method name=Fahrenheit>
<PARAMETER name=C/>
</method>
</implements>
<SCRIPT LANGUAGE=VBScript>
Function Celsius(F)
Celsius = 5/9 *(F - 32)
End Function
Function Fahrenheit(C)
Fahrenheit =(9/5 * C)+ 32
End Function
</SCRIPT>
</SCRIPTLET>
使用这个Windows指令元件之前,必须将这个档案以.sct为副档名储存起来,然後在Windows档案总管中,在这个档案上按下滑鼠右钮,并选取 登录 。如果要在Web网页中使用这个元件,则必须使用像底下这样的一个伺服器端指令:
<%
Option Explicit
Dim objConvert
Dim sngFvalue, sngCvalue
sngFvalue = 50
sngCvalue = 21
Set objConvert = Server.CreateObject("ConvertTemp.Scriptlet")%>
<%= sngFvalue %> degrees Fahrenheit is equivalent to <%= objConvert.
Celsius(sngFvalue)%> degrees Celsius<BR>
<%= sngCvalue %> degrees Celsius is equivalent to <%= objConvert.
Fahrenheit(sngCValue)%> degrees Fahrenheit<BR>
使用ASP内建物件
ASP也提供可以执行有助於工作的内建物件,以简化Web的开发程序。例如,您可以用 Request 物件轻松地存取与HTTP要求有关的资讯,例如来自HTML表单或cookie的使用者输入。与使用由COM元件提供的物件不同的是,您不必建立ASP内建物件的例项,就可以将它用在指令中。ASP 在开始进行处理时,就会自动为您建立这些物件。存取内建物件和属性的方式,跟本文所描述的存取元件物件和属性的方式一样。若需有关内建物件的完整说 明,请参阅本章最後的
〈Active Server Pages物件速查卡〉 。
呼叫物件方法
所谓 方法 是指您可以在物件上、或者用物件执行的一个动作。呼叫方法的语法如下:
Object.Method parameters
parameters会因方法而有所不同。
例如,您可以如下列陈述式所示,利用 Response 内建物件的 Write 方法传送资讯给浏览器:
<% Response.Write "Hello World" %>
说明
某些指令语言不支援 Object.Method 语法。如果您的语言不支援,就必须新增一个项目到登录中,以便用该语言作为您的主要指令语言。若需其他资讯,请参阅之前 〈使用指令语言〉 。
设定物件属性
所谓 属性 指用来描述物件的属性。属性定义了物件的特性,例如物件的类型、或者描述物件的状态,例如启用或者停用。其语法如下:
Object.Property
有时候您可以读取和设定属性的值。除此之外,有些物件也可以新增属性。
例如,Ad Rotator元件有一个叫做 Border 的属性,可以用来指定广告是否要有边界,以及决定边界的宽度。底下这个运算式表示不要边界:
<% MyAds.Border = 0 %>
对於某些属性,您可以用ASP输出指引来显示目前的值。例如,如果浏览器还连接在伺服器上,下列陈述式会传回TRUE:
<%= Response.IsClientConnected %>
从Java类别建立物件
如果要用 Server.CreateObject 建立一个Java类别的例项,就必须用JavaReg程式将类别登录成一个COM元件。然後您便可以将 Server.CreateObject 方法或者一个HTML<OBJECT> 标签跟 PROGID或CLSID配合使用。
另一种方法是,用Java别名(moniker)提供的机制直接为Java类别建立例项,而不使用JavaReg程式。如果要以别名为类别建立例项,就要使用VBScript 或JScript的 GetObject 陈述式,并以java:classname的格式提供Java 类别的完整名称。下列这个VBScript范例会建立一个Java Date类别的例项。
<% Dim dtmDate Set dtmDate = GetObject("java:java.util.Date") %> The date is <%= dtmDate.toString()%>
以呼叫 GetObject 而不是呼叫 Server.CreateObject 的方式建立的物件也可以存取ASP内建物件,并参与异动。不过,如果要使用Java别名,您必须使用2.0版或者更新版的Microsoft 虚拟机器。
设定物件领域
物件的领域(scope)指的是该物件可以被哪些指令所使用。在预设情况下,物件例项被建立时,领域为网页领域。同一个ASP网页中的任何指令命令,都可以使用该网页领域的物件,当 .asp档案处理完使用者的要求之後,物件便会被释放。网页领域是一般建议给物件使用的领域。您也可以视需要变更物件的领域,让物件也能给其他网页中的指令存取。本文将告诉您如何使用网页领域物件,以及如何变更物件的领域。
使用网页领域物件
在ASP网页上利用 Server.CreateObject 或HTML的 <OBJECT> 标记建立的物件,在该网页的整个使用过程中都会一直存在。物件可以让该网页中的任何指令命令使用。当ASP处理完这个网页时,此物件也会随之被释放。因此这种物件的领域或寿命(lifetime)与网页相同。
在回圈中建立物件
一般而言,应该尽量避免在回圈中建立物件。如果您真的必须在回圈中制造物件,请务必记得将该物件所用到的资源释放:
<%
Dim objAd
For i = 0 To 1000
Set objAd = Server.CreateObject("MSWC.AdRotator")
.
.
.
objAd.GetAdvertisement
.
.
.
Set objAd = Nothing
Next
%>
将物件设定为工作阶段领域
工作阶段领域 (session-scope)物件是针对应用程式中每一个新的工作阶段所建立的,当工作阶段结束时也会跟着被释放,因此每一个使用中的工作阶段都有一个物件。当物件会被好几个指令呼叫,但影响到的都是同一个使用者工作阶段时,这种物件就适合设定成工作阶段领域。建议您最好只在必要时才将物件设定为工作阶段领域。当您使用工作阶段领域时,也一定要了解提供此物件的元件执行绪模型,因为执行绪模式会影响物件的效能与安全。若需其他资讯,请参阅之後的
〈进阶资讯:效能问题〉 。要将物件设定为工作阶段领域,可将物件存放在ASP的内建物件 Session 中。在Global.asa档案中使用HTML的 <OBJECT> 标记,或在ASP网页中使用 Server.CreateObject 方法,都可以建立工作阶段领域的物件例项。
在Global.asa档案中,您可以利用 <OBJECT> 标记建立工作阶段领域的物件,此标记的RUNAT属性与SCOPE属性必须分别设定成SERVER与 Session。以下范例会替Browser Capabilities(浏览器功能)元件的Browser Type (浏览器类型)物件建立一个工作阶段领域的例项:
<OBJECT RUNAT=SERVER SCOPE=Session ID=MyBrowser PROGID="MSWC.
BrowserType">
</OBJECT>
当您将物件存放到 Session 物件中之後,就可以在应用程式的任何一个网页中存取此物件。例如以下的陈述式就会使用到前一个范例用 <OBJECT> 标记建立的物件例项:
<%= If MyBrowser.browser = "IE" and MyBrowser.majorver >= 4 Then . . .%>
在ASP网页中,您也可以用 Server.CreateObject 方法将物件存放在内建物件 Session 内。例如以下范例便可将Browser Type物件的一个例项存放在 Session 物件内。
<% Set Session("MyBrowser")= Server.CreateObject("MSWC.
BrowserType")%>
若要在另一个 .asp档案中显示浏览器资讯,首先应把存放在 Session 物件中的 BrowserType 物件例项取出,然後呼叫 Browser 方法将浏览器的名称显示出来:
<% Set MyBrowser = Session("MyBrowser")%> <%= MyBrowser.browser %>
利用 <OBJECT> 标记建立的物件尚未被 .asp档案的指令命令使用之前,ASP不会对该物件作例项化的动作。 Server.CreateObject 方法则可立刻将物件例项化。因此 <OBJECT> 标记提供给工作阶段领域物件的延展性比 Server.CreateObject 方法提供的更好。
将物件设定为应用程式领域
应用程式领域 (application-scope)物件是应用程式启动时所建立的物件例项,为物件唯一的一个例项。此物件可让所有的用户端要求共用。某些公用程式物件,例如网页计数元件(Page Counter Component)的物件,在应用程式领域中的表现可能较好,但一般而言,最好采用下一个小节建议的其他替代方法。此外,执行绪模式也会影响物件的效能与安全性(请参阅稍後的〈进阶资讯:效能问题〉)。
要将物件设定为应用程式领域,只要将物件存放在ASP的内建物件 Application 中,以後便可利用Global.asa档案中的 <OBJECT> 标记或 .asp档案中的 Server.CreateObject 方法,建立应用程式领域的物件例项。
在Global.asa档案中,您可以用 <OBJECT> 标记建立应用程式领域的物件,此标记的RUNAT属性与SCOPE属性必须分别设定成Server与 Application。例如以下范例就是利用 <OBJECT> 标记建立出一个应用程式领域的AdRotator物件例项:
<OBJECT RUNAT=SERVER SCOPE=Application ID=MyAds PROGID="MSWC.AdRotator"> </OBJECT>
将Ad Rotator物件存入Application状态後,在应用程式的任何网页中用类似以下的叙述便可存取此物件例项:
<%=MyAds.GetAdvertisement("CustomerAds.txt")%>
此外,在.asp档案中,您还可以用 Server.CreateObject t将物件例项存入内建物件 Application 中,如以下范例所示:
<% Set Application("MyAds")= Server.CreateObject("MSWC.Adrotator")%>
您可以从Application状态中将此 Ad Rotator 物件例项取出,在应用程式的.asp档案内显示广告画面,如以下范例所示:
<%Set MyAds = Application("MyAds")%> <%=MyAds.GetAdvertisement
("CustomerAds.txt")
%>
工作阶段领域与应用程式领域之外的其他方法
一般而言,对於需要长时间进行初始化动作的项目或物件,例如字典物件或记录集(recordset),最好尽量使用应用程式状态或工作阶段状态。但如果工作阶段状态或应用程式状态的物件消耗过多的资源,例如记忆体或资料库连接个数,则应改用其他方法建立这些物件。举例来说,元件的执行绪模式会影响根据它建立出来之物件的效能,尤其是这些物件又设定为工作阶段领域或应用程式领域时,所受到的影响更是深远。
在许多状况下,利用工作阶段领域或应用程式领域的变数把资讯传给网页而建立的物件,要比直接建立应用程式领域或工作阶段领域的物件好得多。例如 ADO的 Connection 物件就不应该设定成工作阶段领域或应用程式领域,因为这会使得该物件建立的连接保持在开启状态,并维持一段很长的时间,但是指令再也不会利用到连接集区。不过,您可以将ODBC或OLE DB连接字串存放在 Session 或Application内建物件内,然後再从其中取出连接字串,据以设定在网页中建立之Connection物件例项的属性。利用这种方法,可将经常用到的资讯存放在工作阶段状态或应用程式状态,但只在必要时才建立用到这些资讯的物件。若需有关设定变数领域的其他资讯,请参阅之前 〈使用变数和常数〉 部分。
使用者定义的JScript物件
您也可以建立自己的JScript物件,只要定义好一个负责建立与初始化新物件的属性与方法之建构函数即可。当指令用 New 运算子呼叫此建构函数时,便可建立物件例项。使用者定义的JScript物件可在ASP伺服器端指令中使用,只要将其设定为网页领域,便可正常运作。但请务必记住,这类由使用者定义的物件不可以设定成应用程式领域。此外,由使用者定义的JScript物件也不可以设定成工作阶段领域,否则会影响物件的正常功能。特别是当这种物件被设定成工作阶段领域时,其他网页中的指令虽然可以存取此物件的属性,但却无法呼叫物件的方法。将使用者定义的JScript物件设定为工作阶段领域,将会对Web应用程式的效能有不利的影响。
进阶资讯:效能问题
元件的执行绪模式对於网站的效能往往有一定程度的影响。一般而言,如果您在 .asp档案中使用的物件会被存入 工作阶段 或 应用程式 状态,建议您使用标示为Both的物件。至於单一执行绪、 Apartment以及自由执行绪(free-threaded)物件则不建议使用。
由於您对使用到的物件之执行绪模式不见得能够时时刻刻予以完全掌控,因此本文特别提出以下建议,希望能帮您获得最佳的效能:
传送内容到浏览器
ASP网页中的指令接受处理时,任何不在ASP分隔字元或 <SCRIPT> 标记之间的文字或图形都会被送回浏览器。您也可以特别利用 Response 物件将内容传送给浏览器。
传送内容
如果要从ASP分隔字元内或者从程序中传送内容到浏览器,请使用 Response 物件的 Write 方法。例如,底下的陈述会根据使用者以前是否造访过网页,而传送不同的欢迎讯息:
<%
If blnFirstTime Then
Response.Write "<H3 ALIGN=CENTER>Welcome to the Overview Page.
</H3>"
Else
Response.Write "<H3 ALIGN=CENTER>Welcome Back to the Overview Page.
</H3>"
End If
%>
如果是在程序之外,就不必使用 Response.Write 将内容传回给使用者。不在指令分隔字元内的内容会被直接传送至浏览器,後者则会设定格式并显示这些内容。例如,底下的指令会产生跟前一个指令相同的输出:
<H3 ALIGN=CENTER> <% If blnFirstTime Then %> Welcome to the Overview Page. <% Else %> Welcome Back to the Overview Page. <% End If %> </H3>
如果只需要传回输出一次,或者新增陈述式至现有的HTML文字中比较方便,您就可以将指令命令配置在HTML中使用。如果不想用分隔字元打断陈述式,或者是想要建构传回至浏览器的字串,就要使用 Response.Write 。例如,您可以建立一个文字字串,利用HTML表单传送的值建构表格的列:
Response.Write "<TR><TD>" & Request.Form("FirstName")_ & "</TD><TD>" & Request.Form("LastName")& "</TD></TR>"
Request.Form 会传回HTML表单传送的值(请参阅之前
〈处理使用者输入〉 )。说明 & 符号是VBScript的字串连结字元。底线(_)是VBScript的命令列接续字元。
设定内容的类型
Web伺服器将档案传回浏览器时,会告诉浏览器档案内容的类型,这样浏览器才知道它是否能够自己显示档案,或者需要呼叫另一个应用程式。例如,如果Web伺服器传回一个Microsoft Excel工作表,浏览器就必须能够启动Microsoft Excel以显示页面。Web伺服器辨识档案类型时会将副档名跟MIME(多功能 Internet邮件副档名)类型清单进行对照。例如,如果要启动Microsoft Excel,浏览器就必须认得application/vnd.ms-excel MIME类型。
您可以用 Response 物件的 ContentType 属性,为您传送给使用者的内容设定HTTP内容类型字串。例如,下列指令会为频道定义设定内容类型:
<% Response.ContentType = "application/x-cdf" %>
若需有关频道的其他资讯,请参阅稍後的 〈建立动态频道〉 。
其他常见的内容类型有text/plain(以文字形式而非解译的HTML陈述式传回的内容)、image/gif(GIF影像)、image/jpeg(JPEG影像)、video/quicktime (Apple QuickTime格式的影片),以及text/xml(XML文件)。除此之外,Web 伺服器或者Web浏览器也可以支援自订的MIME类型。如果想看看您的Microsoft Web伺服器已经定义好的内容类型,请使用Internet Information Services嵌入式管理单元,来开启您的Web站台的内容页,为此,请按一下 HTTP标题 标签页,再按一下 档案类型 标签页。当您选择以ASP自行设定内容类型时,可以用这些档案类型作为参考。
重新导向浏览器
您可以不将内容传送给使用者,而用 Redirect 方法将浏览器重新导向至另一个URL。例如,如果您希望使用者从首页进入您的应用程式,以便让他们收到一个客户识别码,如此就可以检查他们是否有客户识别码,如果没有,便可以将他们重新导向至首页。
<%
If Session("CustomerID")= "" Then
Response.Redirect "Register.asp"
End If
%>
伺服器端的指令会在任何内容被传送给使用者之前先处理,这就是所谓的 缓冲处理 。ASP可以让您开启或关闭缓冲处理功能,这项设定会对Redirect方法的行为造成很大的影响。尤其,如果您将缓冲处理功能关闭,就必须在您页面的HTTP标题传回浏览器之前,重新导向浏览器。
请将 Response.Redirect 陈述式放在页面顶端,而且是在任何文字或 <HTML> 标记的前面,以确保不会有任何东西被传回浏览器。如果您在内容或标题被传回浏览器之後使用Response.Redirect,便会看到一个错误讯息。此外要注意的是,Response.Redirect後面不需要有一个 Response.End 。
如果您要在页面中间使用 Response.Redirect ,就要搭配 Response.Buffer 属性一起使用,如稍後〈缓冲处理内容〉一节描述的那样。
在 .asp档案之间进行传输
用 Response.Redirect 重新导向浏览器需要来回传输(round-trip),意思是说若伺服器要传送一个HTTP回应给浏览器,表明新URL 的位置,之後浏览器会自动离开伺服器的要求伫列,并为这个URL传送一个新的HTTP要求。然後伺服器会将这个要求跟其他同时到达的用户端要求一起加入要求伫列中。对於一个忙碌的Web站台来说,来回传输会浪费频宽且降低伺服器的性能,尤其是当浏览器被重新导向到同一个伺服器上的档案时。
您可以用 Server.Transfer 方法从一个 .asp档案传输到在同一个伺服器上的另一个档案,而不是使用 Response.Redirect 方法。利用 Server.Transfer ,您可以直接为 .asp档案传输要求,而不必离开伺服器的要求伫列,这样可以消除昂贵的来回传输代价。
例如,底下这个指令说明要如何利用 Server.Transfer ,根据状态资讯在应用程式的页面之间跳跃:
<%
If Session("blnSaleCompleted")Then
Server.Transfer("/Order/ThankYou.asp")
Else
Server.Transfer("/Order/MoreInfo.asp")
End if
%>
Server.Transfer 会从一个执行中的 .asp档案传送要求到另一个档案。在传输进行期间,原先要求的 .asp档案会立刻终止执行,而不清除输出缓冲区(若需其他资讯,请参阅稍後〈缓冲处理内容〉一节)。当目的档案开始执行时,便可以使用要求资讯。在执行的期间,这个档案跟原先提出要求的档案一样,可以存取原有的那些物件( Request、Response、Server、Session 、以及 Application )。
您也可以用 Server.Transfer 在不同应用程式中的 .asp档案之间进行传输。不过,当您传输到另一个应用程式中的 .asp档案时,档案的行为会好像是起始传输动作的应用程式的一部分(也就是说,档案只能存取起始应用程式领域内的变数,而不是档案实际所在处之应用程式的变数)。例如,如果您从Sales Application中的一个档案传输到Personnel Application中的一个档案, Sales Application实际上是从Personnel Application借用这个档案,并将它当成是 Sales Application的一部分来执行。
ASP还提供 Server.Execute 指令,可以让您用来传输到档案、执行其内容,然後传回起始传输的档案。如果您对VBScript很熟悉,将 Server.Execute 看成是一种程序呼叫会很有帮助,不同的是,执行的不是程序,而是整个 .asp档案。
例如,底下的指令说明您可以如何利用 Server.Execute 以动态方式纳入.asp档案:
<%
.
.
.
If blnUseDHTML Then
Server.Execute("DHTML.asp")
Else
Server.Execute("HTML.asp")
End If
.
.
.
%>
只要目的档案属於同一个伺服器上的应用程式,发起的应用程式就会传输到这个档案,执行其内容,然後恢复执行起始传输的档案。跟 Server.Transfer 一样,被执行的 .asp档案的动作会有如发起应用程式的一部分。不过, Server.Execute 不能跨伺服器使用。若需其他资讯,请参阅 Server.Execute 。
缓冲处理内容
根据预设,Web伺服器会在处理页面上的所有指令之後,才将内容传送给使用者。这种处理方式称为 缓冲处理 。您可以使用 Response 物件的 Buffer 属性停用缓冲处理功能,使得 Web伺服器在处理页面时传回HTML和指令的结果。
缓冲处理.asp档案的好处是,万一指令的处理进行不顺利,或者某个使用者没有适当的安全凭证,您便可以终止传送Web网页,而改用 Server.Transfer 将使用者转送到另一个页面,或者清除缓冲区(用 Response 物件的 Clear 方法)。或许您也可以在进行传输之前使用 Clear 方法,不过这要看您的应用程式而定。以下的范例采用了这两种方法:
<HTML>
<BODY>
.
.
.
<%
If Request("CustomerStatus")= "" Then
Response.Clear
Server.Transfer("/CustomerInfo/Register.asp")
Else
Response.Write "Welcome back " & Request("FirstName")& "!"
.
.
.
End If
%>
</BODY>
</HTML>
您也可以用 Response.Buffer 防止Web伺服器在指令可以修改标题之前传回HTTP标题。有些属性和方法,例如 Response.Expires 和 Response.Redirect ,会修改HTTP 标题。
如果指令中的 Buffer 属性被设定为TRUE,而没有呼叫 Flush 方法将暂存的内容立即送到浏览器,伺服器就会保存用户端提出的「持续作用」(Keep-Alive)要求。用这种方式编写指令的好处是可以改进伺服器的效能,因为伺服器不需要为各个用户端要求建立一个新的连线(假如伺服器、用户端和任何Proxy伺服器都支援「持续作用」要求的话)。不过,这种作法的一个潜在缺点是,缓冲处理会阻止伺服器的回应被传送给使用者,直到伺服器完成整个指令的处理为止。对於比较长或者比较复杂的指令,使用者可能要等久一点才能够看到页面。
ASP应用程式预设是启用缓冲处理功能。您可以使用Internet Information Services嵌入式管理单元,将整个ASP应用程式的缓冲处理功能关闭。若需其他资讯,请参阅第3章之
〈设定ASP应用程式〉 。
让Proxy伺服器快取处理页面
您的应用程式可能必须透过一个Proxy伺服器传送页面给用户端。 Proxy 伺服器会为用户端浏览器向Web站台要求页面,之後会快取处理HTML页面,使得重覆要求使用的页面可以快速而且有效率地传回浏览器。让Proxy伺服器处理要求和快取处理页面,可以减少网路和Web伺服器的工作负荷。
虽然快取处理很适合用在很多HTML页面上,却往往不适用於经常要更新资讯的ASP网页。例如,对於股票行情来说,即使一个小时前的资讯都可能已经不够精确了。如果您的应用程式会传回个人化的资讯,例如自订的首页,就必须确定使用者不会看到其他使用者的个人资讯。
预设,ASP会要Proxy伺服器不要快取处理ASP网页本身(不过影像、影像地图、applet以及其他从页面参照的项目都会被快取处理)。您可以利用 Response.CacheControl 属性来设定快取控制HTTP标题栏位,容许对某些页面进行快取处理。 Response.CacheControl 的预设值是字串 "Private",可以防止Proxy伺服器快取处理页面。如果要容许快取处理,就必须将快取控制标题栏位设定为Public:
<% Response.CacheControl = "Public" %>
HTTP标题必须在传送任何页面内容之前传送给浏览器或Proxy程式,因此您可以将 Response.CacheControl 属性摆在任何HTML标记前面,或者如果您已经停用缓冲处理功能,就要用 Response.Buffer 来缓冲处理页面。
快取控制标题栏位是HTTP 1.1规格的一部分。ASP网页不会在只支援 HTTP 1.0的Proxy伺服器上被快取处理,因为这样并不会有过期(Expires)标题栏位被送出去。
防止浏览器快取处理页面
每个浏览器版本都各自有其是否要快取处理页面的规则。如果要防止浏览器快取处理ASP网页,就要用 Response.Expires 来设定过期(Expires)标题:
<% Response.Expires = 0 %>
数值0会迫使快取处理的页面立即过期。HTTP标题必须在送出任何页面内容之前送给浏览器,因此请将 Response.Expires 内容放在任何 HTML标记前面,或者缓冲处理页面。
建立动态频道
频道是可以在Microsoft Internet Explorer 4.0或以後版本上使用的一种Web 技术,可以让您自动传送新的或者更新过的Web内容给使用者。频道可以排定让使用者的电脑定期连线到伺服器去撷取更新的资讯(这种撷取处理通称为用户端拉取(client pull),因为资讯是从伺服器「拉进来」或者收集来的)。当新的资讯可以从特定的Web站台取得时,内容就会被下载到浏览器的快取记忆体中,以便於离线阅览。善用频道分送以Web为基础的资讯(尤其是在企业内部网路上),有助於将资讯集中化,而且可以减少伺服器的流量。若需有关频道的其他资讯,请到Microsoft Internet Explorer站台:
http://www.microsoft.com/windows/ie/ 。利用ASP,您可以藉由编写指令产生一个频道定义档,以动态的方式建立频道。一个以XML为基础的频道定义档(.cdf)描述了频道内容的组织并更新排程。.cdf档案中的指令采用类似HTML标记的语法,所以很容易学,也很容易从指令产生。编写伺服器端指令以建立频道定义档时,必须以.cdx为副档名。 ASP读取副档名为 .cdx的档案时,会自动传送application/x-cdf档案类型,要浏览器将位元组当成频道定义解译。如果不用 .cdx副档名,您的指令就必须自行将内容类型用 Response.ContentType 设定为application/x-cdf。
以下是一个使用频道的范例。下列HTML表单会要求使用者选取频道。在表单送出去之後,会呼叫 .cdx档案中的一个指令,以建立频道定义。
<P> Choose the channels you want. </P> <FORM METHOD="POST" ACTION="Chan.cdx"> <P><INPUT TYPE=CHECKBOX NAME=Movies> Movies <P><INPUT TYPE=CHECKBOX NAME=Sports> Sports <P><INPUT TYPE="SUBMIT" VALUE="SUBMIT"> </FORM>
Chan.cdx中的指令会根据要求送出的表单数值建立频道定义。
<% If Request.Form("Movies")<> "" Then %>
<CHANNEL>
电影页面的频道定义陈述式
</CHANNEL>
<% End If %>
<% If Request.Form("Sports")<> "" Then %>
<CHANNEL>
运动页面的频道定义陈述式
</CHANNEL>
<% End If %>
以WebDAV存取伺服器资源
分散式写作和版本处理 (Distributed Authoring and Versioning, WebDAV)是HTTP 1.1协定的一个强大延伸功能,可以透过HTTP 连线公开Web档案储存媒体,例如一个本机档案系统。WebDAV能使得Web成为一个毫无瑕疵的合作式写作环境。在IIS 5.0中已经采用WebDAV,您可以让远端的作者在您的Web伺服器上的档案和目录中建立、删除、移动、搜寻或者套用属性。若需其他资讯,请参阅第3章之 〈WebDAV发行〉 。
包含档
利用伺服器端包含指令,可以在Web伺服器还没处理档案之前,把其他档案的内容插入要传给用户端的档案内。ASP仅支援此种机制中的 #Include 指令。请用以下语法将另一个档案插入 .asp档案内:
<!-- #include virtual | file ="档名" -->
以上语法中的 virtual 与 file 两个关键字表示用来纳入档案的路径种类,档名则是要引入的档案之路径与档案名称。
包含档案本身并不一定要用特殊的副档名,但一般而言,将包含档案的副档名设定成 .inc,以便与其他种类的档案区分,是比较好的设计习惯。
使用Virtual关键字
virtual 关键字的用途是设定虚拟目录开头的路径。举例来说,假设虚拟目录 /Myap内有一个Footer.inc档案,则在档案中加上以下这行程式,便可将Footer.inc的内容纳进来:
<!-- #include virtual ="/myapp/footer.inc" -->
使用File关键字
file 关键字的用途是设定 相对 路径,也就是从档案本身目前所在目录开始,到欲纳入之档案所在目录的路径。举例来说,如果您的档案在Myapp这个目录内,而Header1.inc位在Myapp\Headers目录内,则以下这行程式就可以将Header1.inc插入您的档案内:
<!-- #include file ="headers\header1.inc" -->
请注意,指定包含档案时所用的路径Headers\header1.inc,就是与您的档案所在目录的 相对 路径;如果 #Include 陈述式所在的程式不在/Myapp目录内,则以上陈述式就没有作用。
使用 file 关键字时,如果您已经在Internet Information Services嵌入式管理单元中选取了 启用上层路径 选项,还可以用(..\)这种语法将上一层目录或更高层目录中的档案纳入进来。若需相关指示, 请参阅第3章之
〈设定ASP应用程式〉 的说明。
包含档的位置
无论档案位於哪一个路径内,只要档案的内容有变化,ASP都能自动侦测到,并且在下一次浏览器要求含有此档案的 .asp档案时,将档案新的内容传给浏览器。但一般而言,若能将包含档案集中放在同一个应用程式目录或Web网站内,可以让包含档案比较安全些。如果要做到更完善的保护,建议您将包含档案放在应用程式中的单独一个目录内,例如 \Includes,并对这个目录只开放适当的执行(Web伺服器)权限。若需其他相关资讯,请参阅 〈设定Web伺服器的权限〉 。
重要
在预设情况下,Web伺服器对所有档案均具有读取的权限。但为了避免使用者看到您所纳入的档案内容,最好取消Include目录的读取权限。
包含档之使用技巧与注意事项
包含档本身也可以将其他档案纳入到自己本身。此外,.ASP档案也可以多次重覆纳入同一个档案,只要所有的 #Include 指令不会造成回圈的情形即可。例如First.ASP档案纳入Second.inc这个档案,则Second.inc就不可以纳入First.asp,也不可以把自己包含进来。ASP会侦测这类的回圈或巢状错误,并於侦测到这种情形时产生错误讯息,同时停止处理所要求的 .asp档案。
ASP是先将指定的包含档纳入,然後才执行指令命令,因此您不可以用指令命令来组成要纳入之档案的名称。举例来说,在以下这个指令中,由於ASP 会先执行 #Include 指令,然後才将档案名称设定给变数name,因此以下这个指令并不会开启Header1.inc这个档案。
<!-- 这个指令无效 --> <% name=(header1 & ".inc")%> <!-- #include file="<%= name %>" -->
指令命令与程序必须整个包含在 <% 与 %>、HTML标记 <SCRIPT>与 </SCRIPT>、或HTML标记 <OBJECT> 与 </OBJECT> 等成对的分隔符号内。换句话说,.ASP档案中若含有分隔符号的左半部分,其相对应的右半部分不可以放在欲纳入的包含档内,这样是错误 的。指令或指令命令必须完整,不可以分散在不同档案内。例如以下这个指令就没有作用:
<!-- 这个指令无效 -->
<%
For i = 1 To n
主档案中的陈述式
<!-- #include file="header1.inc" -->
Next
%>
但以下这个指令就可以顺利执行:
<%
For i = 1 to n
主档案中的陈述式
%>
<!-- #include file="header1.inc" -->
<% Next %>
说明
如果您的ASP指令纳入的档案含有很多函数与变数,但这些函数与变数在您的ASP程式中都不会用到,则这些没用到的结构所占用的额外资源对伺服器的效能将有不利的影响,会降低Web应用程式的延展性。因此一般建议最好将包含档案打散成好几个比较小的档案,如此就不必在伺服器端指令内引入一个或两个含有过多不需用到资讯的大档案,只要将必要的档案纳入即可。
有时候您可以用HTML的 <SCRIPT></SCRIPT> 标记将伺服器端的档案纳入进来。例如以下这个指令就用相对路径的方式,纳入一个可以让伺服器执行的档案:
<SCRIPT LANGUAGE="VBScript" RUNAT=SERVER SRC="Utils\datasrt.inc"></SCRIPT>
下表列出在虚拟路径以及相对路径两种状况下,用SRC属性纳入档案的正确语法:
| 路径类型 | 语法 | 范例 |
|---|---|---|
| 相对路径 | SRC="路径\档名" | SRC="Utilities\Test.asp" |
| 虚拟路径 | SRC="/路径/档名" | SRC="/MyScripts/Digital.asp" |
| 虚拟路径 | SRC="\路径\档名" | SRC="\RegApps\Process.asp" |
说明
用这种方法纳入档案时,不可以在 <SCRIPT> 标记内放入任何程式码;如果您真的需要这种功能,请额外多加一组 <SCRIPT> 标记。
管理工作阶段
开发成功的Web应用程式的挑战之一,便是维护使用者在应用程式的页面拜访期间或工作阶段期间的资讯。HTTP是一种无状态的通讯协定,也就是说您的Web伺服器将页面的每个HTTP要求都当作独立要求来处理;伺服器完全不保留先前要求的认知,即使是在现行要求之前数秒钟提出的要求也一样。不具有记忆先前要求的能力,表示难以撰写诸如线上类别目录等的应用程式,因为这种应用程式可能需要追踪使用者在各个类别目录页面之间切换时所选取的类别目录项目。
ASP提供了管理工作阶段资讯问题的唯一解决方案。使用ASP的 Session 物件和伺服器产生的特殊使用者ID,就可以建立出聪明的应用程式,它可以识别各个访客,并 集应用程式稍後可用来追踪使用者细项设定或选择的资讯。
重要
ASP使用HTTP cookie来指定使用者ID,而cookie是储存在使用者浏览器上的小档案。因此,若要建立用於不支援cookie的浏览器的应用程式,或者客户可能将浏览器设定为拒绝cookie,就不应使用ASP的工作阶段管理功能。
启动和结束工作阶段
工作阶段可用四种方式启动:
如果使用者在指定的时间内并未重新要求或重新整理应用程式中的页面,就会自动结束工作阶段。此数值预设为20分钟。藉由设定Internet Information Services嵌入式管理单元中 应用程式选项 内容页的 工作阶段逾时时间 属性,即可变更该应用程式的预设值。请依据Web应用程式和伺服器的记忆体容量来设定此值。例如,如果预期浏览Web应用程式的使用者只在每页逗留数分钟,则可能要大幅减少预设的工作阶段逾时时间。太长的工作阶段逾时时间会导致开启太多工作阶段,如此会过度耗用伺服器的记忆体资源。
若在指定的工作阶段中,想要将逾时时间设定为比预设的应用程式逾时时间还短,则可以设定 Session 物件的 Timeout 属性。例如,下列指令将逾时时间设定为5分钟。
<% Session.Timeout = 5 %>
您也可以将逾时时间设定为大於预设值,此值由 Session Timeout 属性来决定。
说明
逾时时间 只适用於具有状态的工作阶段。在无状态工作阶段期间, Session 物件不包含内容或静态物件。在处理要求并在同一浏览器重新建立下一个要求之後,就会自动结束这种工作阶段。
或者,若要故意结束工作阶段,您可以使用 Session 物件的 Abandon 方法。例如,您可以在表单中提供 结束 按钮,此表单将ACTION参数设定为包含下列指令的 .asp档案的URL。
<% Session.Abandon %>
说明
排定在开始Session.Abandon之前执行的使用者要求,将会在放弃的工作阶段内容中执行。当Session.Abandon执行完成之後,新进的要求就与此工作阶段无关。
关於SessionID和Cookie
使用者第一次在指定的应用程式中要求 .asp档案时。ASP便会建立 SessionID。SessionID是经过复杂运算之後所获得的数字,可用来唯一地识别各使用者的工作阶段。在开始新工作阶段时,伺服器会将SessionID当作cookie储存在使用者的Web浏览器中。
SessionID cookie类似储物柜的钥匙,当使用者在工作阶段期间与应用程式互动时,ASP可以将使用者资讯储存在伺服器的「储物柜」中。在HTTP要求标题中传输的使用者SessionID cookie,可让您存取资讯,就像储物柜钥匙可让您取得储物柜中的内容物一样。每次ASP收到页面的要求时,就会检查SessionID cookie的HTTP要求标题。
将SessionID cookie储存在使用者的浏览器之後,ASP会使用同一个cookie 来追踪工作阶段,甚至使用者要求另一个 .asp档案或要求在其他应用程式中执行的 .asp档案也一样。同理,如果使用者故意放弃或让工作阶段逾时,然後要求另一个 .asp档案,则ASP仍会使用相同的cookie来开始新的工作阶段。只有伺服器管理员重新启动伺服器而清除记忆体中储存的SessionID设定值时,或使用者重新启动Web浏览器时,使用者才会收到新的SessionID cookie。
藉由重覆使用SessionID cookie,ASP使传送至浏览器的cookie数目变得最少。此外,如果让您的ASP应用程式不要求工作阶段管理,则可以避免ASP 追踪工作阶段和传送SessionID cookies给使用者。
在下列状况下,ASP不会传送工作阶段cookie:
<%@ EnableSessionState=False %>
若需其他资讯,请参阅稍後之 〈无工作阶段的ASP网页〉 一节。
您应该也注意到,SessionID cookie并未提供多次拜访Web站台时追踪使用者的永久方法。因此储存在伺服器记忆体中的SessionID资讯很容易失去。若要追踪长期拜访Web应用程式的使用者,就必须在使用者的Web浏览器中储存特殊的cookie,并将此cookie资讯储存至资料库中,以建立使用者识别码。若需其他资讯,请参阅稍後 〈使用cookie〉 一节。
储存和移除Session物件中的资料
Session 物件提供动态的联合阵列,可让您将资讯存入其中。您可以将纯量变数和物件变数存入 Session 物件中。
若要将变数存入 Session 物件,请指定数值至 Session 物件的具名项目中。例如,下列指令会将两个新变数存入 Session 物件中:
<% Session("FirstName")= "Jeff" Session("LastName")= "Smith" %>
若要撷取 Session 物件的资讯,请存取具名项目。例如,若要显示Session ("FirstName")目前的值:
Welcome <%= Session("FirstName")%>
您可以将使用者的喜好设定储存在 Session 物件中,然後存取该喜好设定以决定要传送给使用者的页面。例如,您可在应用程式的第一页让使用者指定纯文字内容,然後将这个选择套用至使用者在此应用程式中所拜访的所有後续页面上。
<% If Session("ScreenResolution")= "Low" Then %> 这是文字版本的页面。 <% Else %> 这是多媒体版本的页面。 <% End If %>
虽然会影响到伺服器的效能,但您也可以将物件例项存入 Session 物件中。若需其他资讯,请参阅之前 〈设定物件领域〉 一节。
有时候您可能希望删除储存在 Session 物件中的项目。例如,对拜访线上零售商店的使用者而言,变更心意、放弃采购项目清单和决定完全不同的选择都是司空见惯的事。在这种状况下,删除不适当的值就能很方便地更新 Session 物件。
Session 物件的 Contents 集合包含工作阶段中已经储存的所有变数(亦即不是使用HTML<OBJECT> 标记储存的变数)。利用 Contents 集合的 Remove 方法,可以选择性地移除工作阶段状态加入的变数参照。下列指令将说明如何使用 Remove 方法从 Session 物件清除项目,此例为移除使用者帐户资讯:
<%
If Session.Contents("Purchamnt")<= 75 then
Session.Contents.Remove("Discount")
End If
%>
如果需要的话,也可以使用 Contents 集合的 RemoveAll 方法完全移除工作阶段中所储存的变数:
Session.Content.RemoveAll()
使用 Remove 方法时,可以选择依名称或索引来删除项目。下列指令示范如何循环变更储存在 Session 物件中的值,然後有条件地依索引来移除数值:
<%
For Each intQuote in Session.Contents
If Session.Contents(intQuote)< 200 Then
Session.Contents.Remove(intQuote)
End If
Next
%>
管理横跨多个伺服器的工作阶段
ASP工作阶段资讯储存在Web伺服器中,所以浏览器必须向同一部Web 伺服器的页面要求存取工作阶段资讯的指令。在Web伺服器的丛集(许多Web 伺服器在此分担回应使用者要求的责任)上,使用者的要求并不会都送到同一部伺服器,反而特殊的软体会将站台URL的所有要求配送至可用的伺服器,此程序称为 负载平衡 。负载平衡使得工作阶段资讯难以保留在Web伺服器的丛集上。
若要在负载平衡的站台中使用ASP工作阶段管理,您必须确定使用者工作阶段中的所有要求都导引至同一部Web伺服器。其中一个办法是撰写 Session_OnStart 程序,此程序使用 Response 物件将浏览器重新导引至执行使用者工作阶段的特定Web伺服器。如果应用程式页面中的所有连结都是相对连结,则未来对於页面的要求都会导引至同一部伺服器。
例如,使用者可用要求站台的一般URL来存取应用程式: http://www.microsoft.com。负载平衡程式会将要求转送至指定的伺服器,例如 server3.microsoft.com。ASP便会在该伺服器建立新的使用者工作阶段。在 Session_OnStart 程序中,会将浏览器重新转送至指定的伺服器:
<% Response.Redirect("http://server3.microsoft.com/webapps/
firstpage.asp")%>
接着浏览器会要求指定的页面,而所有後续的要求都会转送至同一部伺服器,只要原始URL未参照指定的伺服器名称。
使用cookie
cookie是Web伺服器内嵌在使用者Web浏览器中用来识别使用者的 token。下次相同的浏览器要求页面时,就会传送从Web伺服器收到的cookie。 cookie可让一组资讯与使用者有所关联。藉由ASP指令可以取得和设定cookie 的值,只要利用 Response 和 Request 物件的 Cookie 集合即可。
设定Cookie
若要设定cookie的值,请使用 Response.Cookies 。如果cookie不存在, Response.Cookies 就会建立新的cookie。例如,若要将称为"VisitorID" 的cookie中相关的值 "49" 传送至浏览器,请使用下列指令,请注意。这个指令必须出现在Web网页的 <HTML> 标记之前:
<% Response.Cookies("VisitorID")= 49 %>
若要让cookie只用於目前使用者工作阶段,则您只需传送cookie至浏览器。不过,若在使用者停止和重新启动浏览器之後,还要能识别使用者,就必须强制浏览器将cookie储存在用户端电脑硬碟的档案中。若要储存cookie,请使用 Response.Cookies 的 Expires 属性,并将日期设定为未来的某个日子:
<% Response.Cookies("VisitorID")= 49 Response.Cookies("VisitorID").Expires = "December 31, 2001" %>
一个Cookie可以有好几个值;这种cookie称为索引cookie。索引cookie 的值被指定为识别码;或是您也可以设定特殊的cookie键值。例如:
<% Response.Cookies("VisitorID")("49")= "Travel" %>
如果现有的cookie具有键值,但 Response.Cookies 并未指定识别码名称,则会删除现有的键值。同理,如果现有cookie不具有键值,但 Response.Cookies 指定其识别码名称,则会删除cookie的目前值,然後建立新的键值组。
取得Cookie
若要取得cookie的值,请使用 Response.Cookies 集合。例如,如果使用者的HTTP要求设定VisitorID=49,则下列陈述式会撷取值49:
<%= Request.Cookies("VisitorID")%>
同理,若要从索引cookie撷取键值,请使用识别码名称。例如,如果使用者的浏览器在HTTP要求标题中传送下列资讯:
Cookie: VisitorID=49=Travel
下列陈述式就会传回值 Travel :
<%= Request.Cookies("VisitorID")("49")%>
设定cookie路径
由ASP储存在使用者Web浏览器的每个cookie都包含了路径资讯。当浏览器要求储存在cookie指定路径中的档案时,浏览器就会自动将cookie转送至伺服器。在预设情况下,cookie路径会对应於包含最先建立此cookie的 .asp档案的应用程式名称。例如,如果储存在应用程式中称为UserApplication的 .asp 档案建立cookie,则每次使用者的Web浏览器撷取该应用程式中的任何档案时,除了包含路径/UserApplication的任何其他cookie之外,浏览器还会转送此 cookie。
若要指定cookie路径而不是预设的应用程式路径,则可以使用ASP Response.Cookies 集合的 Path 属性。例如,下列的指令会将路径 SalesApp/Customer/Profiles/ 指定至称为Purchases的cookie:
<% Response.Cookies("Purchases")= "12" Response.Cookies("Purchases").Expires = "January 1, 2001" Response.Cookies("Purchases").Path = "/SalesApp/Customer/Profiles/" %>
每当包含Purchases cookie的Web浏览器要求路径 /SalesApp/Customer/Profiles/ 或其任何子目录中的档案时,浏览器就会转送 cookie至伺服器。
许多Web浏览器都会保留cookie路径的大小写,包括Microsoft Internet Explorer 4.0版或更新版本,以及Netscape浏览器。这表示如果要求的档案路径大小写与储存的cookie路径大小写不同,浏览器就不会传送cookie至伺服器。例如,对ASP而言,虚拟目录 /TRAVEL与 /travel是指相同的ASP应用程式,但对保留URL大小写的浏览器而言,/TRAVEL和 /travel是两个不同的应用程式。请确定所有 .asp档案的URL都具有相同的大小写,以让使用者的浏览器转送储存的cookie。
您可以使用下列陈述式来设定cookie路径,让使用者的Web浏览器每次要求伺服器的档案时都会转送cookie,而与应用程式或路径无关:
Response.Cookies("Purchases").Path = "/"
不过,请将cookie转送至伺服器,而不要区分应用程式,因为如果cookie 包含了不该给除了指定的应用程式以外的敏感资讯,则会造成潜在的安全问题。
不使用Cookie保留状态
并非所有的浏览器都支援cookie。即使使用支援cookie的浏览器,部分使用者仍比较喜欢关闭cookie支援。如果应用程式需要回应不支援cookie的浏览器,就不能使用ASP工作阶段管理。
此时必须自行撰写在应用程式的页面之间传送资讯的机制。一般而言有两种做法: 不过,如果以GET方法来提送表单,部分浏览器会舍弃查询字串中传送的任何明确参数。
http://MyServer/MyApp/start.asp?name=Jeff
<FORM METHOD="POST" ACTION="/scripts/inform.asp"> <INPUT TYPE="text" NAME="city" VALUE=""> <INPUT TYPE="text" NAME="country" VALUE =""> <INPUT TYPE="hidden"NAME="userid" VALUE= <%= UserIDNum(i)%> <INPUT TYPE="submit" VALUE="Enter">
此方法要求传送使用者资讯的所有连结目标都以HTML表单来编码。
若未使用ASP工作阶段管理,应该关闭应用程式的工作阶段支援。在启用工作阶段时,ASP会传送SessionID cookie给要求页面的每个浏览器。若要关闭工作阶段支援,请清除Internet Information Services 嵌入式管理单元中 应用程式选项 内容页中的 启用作业状态 核取方块。
无工作阶段的ASP网页
您也可以使用ASP来建立无工作阶段的页面,此页面可以在需要时才建立工作阶段。
无工作阶段页面并不会执行下列各项:
若要将 .asp档案设定为无工作阶段,请使用下列指令:
<%@ EnableSessionState=False %>
您应该将此指令放在 .asp档案的第一行,在任何其他指令之前。忽略此标记时,预设会启用工作阶段追踪。
无工作阶段的ASP网页通常可以藉由消除潜在的耗时工作阶段活动来改善伺服器的回应速度。以下列包含两个HTML框架的ASP网页为例:框架1和 2都在同一个框架组中。框架1包含执行复杂指令的 .asp档案,而框架2包含比较简单的 .asp档案。因为ASP依序或连续执行工作阶段要求,因此在框架1的指令完成执行之前,就无法看到框架2的内容。不过,如果使框架1的 .asp档案为无工作阶段,则ASP要求就不再为连续,因此浏览器可以在框架1的内容执行完成之前,就先提送框架2的内容。
很不幸地,处理不同框架的多重要求方法与使用者Web浏览器的设定有很大的关系。某些Web浏览器可能依序处理要求,而不管.asp档案中的无工作阶段设定。
存取资料来源
ActiveX资料物件 (ADO)是种简单、好用又富延展性的技术, Web网页可藉由它向资料库存取资料。我们可利用ADO来撰写精巧又有弹性的指令,来连接和OLE DB相关之资料来源,如资料库、试算表、循序资料档或电子邮件 目录等。OLE DB是一种系统层级之程式设计介面,它提供一套标准的COM介面来公开资料库管理系统功能。只要运用ADO物件模型(用VBScript或JScript 等指令语言),就能很方便的运用这些介面,让Web应用程式拥有存取资料库之功能。除此之外,ADO还可用来存取和 开放式资料库连接 (Open Database Connectivity,ODBC)相关之资料库。
如果您只是位指令程式设计师,对资料库的连接并不熟悉,那麽ADO的指令语法对您来说,应是好用而又不复杂。反之,若您对程式开发很有经验,那麽更会认同ADO存取资料来源时,所展现之弹性及高效能表现。
若需有关ADO的其他资讯,请造访Microsoft Universal Data Access(UDA) Web网站:
http://www.microsoft.com/data/ 。
建立连接字串
建立Web资料应用程式的第一步,就是建立一个可供ADO搜寻及辨识资料来源的管道。这个管道是由连接字串来负责。所谓 连接字串,就是一连串由分号区隔开来之引数,用来定义某些参数,如:来源资料提供者及来源资料之所在位置等。ADO利用连接字串来辨别OLE DB提供者,并将它引导至资料来源处。提供者 是元件的一种,它代表资料来源,并以列的形式公开资料给应用程式来运用。
下表列出了一些常用的资料来源OLE DB连接字串:
| 资料来源 | OLE DB连接字串 |
|---|---|
| Microsoft Access | Provider=Microsoft.Jet.OLEDB.4.0;Data Source=至.mdb档案之实体路径 |
| Microsoft SQL Server | Provider=SQLOLEDB.1;Data Source=至伺服器资料库之路径 |
| Oracle | Provider=MSDAORA.1;Data Source=至伺服器资料库之路径 |
| Microsoft Indexing Service | Provider=MSIDXS.1;Data Source=档案路径 |
为提供向後相容性,OLE DB提供者支援ODBC连接字串语法。下表所列,为经常使用到之ODBC连接字串:
| 资料来源驱动程式 | ODBC连接字串 |
|---|---|
| Microsoft Access | Driver={Microsoft Access Driver(*.mdb)};DBQ=至 .mdb档案之实体路径 |
| SQL Server | DRIVER={SQL Server};SERVER=至伺服器之路径 |
| Oracle | DRIVER={Microsoft ODBC for Oracle};SERVER=至伺服器之路径 |
| Microsoft Excel | Driver={Microsoft Excel Driver(*.xls)};DBQ=至 .xls档案之实体路径; DriverID=278 |
| Microsoft Excel 97 | Driver={Microsoft Excel Driver(*.xls)};DBQ=至 .xls档案之实体路径;DriverID=790 |
| Paradox | Driver={Microsoft Paradox Driver(*.db)};DBQ=至 .db档案之实体路径;DriverID=26 |
| Text | Driver={Microsoft Text Driver(*.txt;*.csv)};DefaultDir=至.txt档案之实体路径 |
| Microsoft Visual FoxPro(含资料库容器) | Driver={Microsoft Visual FoxPro Driver}; SourceType=DBC;SourceDb=至 .dbc档案之实体路径 |
| Microsoft Visual FoxPro(不含资料库容器) | Driver={Microsoft Visual FoxPro Driver}; SourceType=DBF;SourceDb=至 .dbf档案之实体路径 |
说明
用UNC路径来引用远端电脑资料来源之连接字串,会有潜在之安全性问题。为防止资料来源受到未经授权之存取,须先为需要存取资料之电脑建立Windows帐户,并引用适当之NTFS权限来存取资料来源。若需其他资讯,请参阅第4章之 〈使用NTFS确保档案的安全性〉 一节。
设计Web资料应用程式应考量之进阶问题
如果Web应用程式是以调阅资料为主,而且同时大量存取资料之使用者在十人以上,那麽建议最好使用主从式资料库引擎,以提高效能及可靠度。虽然 ADO可与任何OLE DB之资料来源搭配使用,然而从密集测试过程看来,它的设计应是和主从式资料库来配合使用的,如:Microsoft SQL Server或Oracle等。
ASP支援共用档案资料库(Microsoft Access或Microsoft FoxPro),并视其为有效资料来源。虽然在某些ASP相关的文件曾有运用到共用档案资料库的例子,不过这类型的资料库引擎,最好只在开发时或在少数特定的情况中才使用。对於需求量及产量品质均有高度要求之Web应用程式,共用档案资料库并不适合主从式资料库模式。
如果您所开发的ASP资料库应用程式有意和远端的SQL Server资料库连接,那麽应注意下列事项:
说明 如果是连接到远端电脑,可使用TCP/IP通讯端来增进效能。
若需有关这些议题的其他资讯,请造访Microsoft Product Support Services 之Web站台 http://www.microsoft.com/support/ 。
连接至资料来源
ADO提供 Connection 物件来建立及处理应用程式与OLE DB相关联之资料来源或ODBC相关之资料库连接问题。 Connection 物件具多种属性及方法,您可用它来开启或关闭资料库之连接,亦可发出更新资讯的查询。
如欲建立资料库连接,请先建立一个 Connection 物件。以下的指令将 Connection 物件例项化,并开启连接:
<% '建立连接物件。 Set cnn = Server.CreateObject("ADODB.Connection") '用OLE DB连接字串来开启连接。 cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C: \MarketData\ProjectedSales.mdb" %>
说明
在连接字串当中,等号(=)前後不可留空白。
在本例当中, onnection 物件之 Open 方法是利用连接字串来完成的。
以连接物件来执行SQL查询
利用 Connection 物件的 Execute 方法,可针对资料来源下达某些指令,如结构化查询语言(SQL)查询(SQL为业界之标准语言,用来和资料库沟通,以及定义指令来撷取与更新资料)。 Execute 方法可接受指定指令(或查询)之参数、资料记录的数量,以及使用指令之类型等。
下列指令的 Execute 方法使用SQL的 INSERT 指令来发出查询,并将资料插入指定之资料库中。在这个例子,指令将姓名Jose Lugo插入称为Customers 的资料库表格中。
<% '定义OLE DB连接字串。 strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Data\Employees.mdb" '启动Connection物件并开启资料库连接。 Set cnn = Server.CreateObject("ADODB.Connection") cnn.Open strConnectionString '定义SQL SELECT陈述式 strSQL = "INSERT INTO Customers(FirstName, LastName)VALUES ('Jose','Lugo')" '使用Execute方法对资料库进行SQL查询。 cnn.Execute strSQL,,adCmdText + adExecuteNoRecords %>
请留意陈述式中有两个参数是用来执行这项查询: adCmdText 及 adExecuteNoRecords 。选择性的参数 adCmdText 参数指定了指令的类型,指出提供者应将查询陈述式(此例为SQL查询)视为指令之文字化的定义。参数 adExecuteNoRecords 则指示ADO在应用程式没有结果传回时,便无须建立资料记录。这个参数只对文字定义型的指令有效,如:SQL查询或内储资料库程序等。虽然 adCmdText 及 adExecuteNoRecords 是选择性的参数,但如果您要用 Execute 来提升应用程式之效能时,就应使用这两个参数。
重要
ADO参数,如 adCmdText ,需要先定义,才能在指令中使用。通常定义参数最方便的方式,就是使用包含了所有ADO参数之定义的元件类型程式库。在使用前,须先宣告该元件类型程式库。宣告ADO类型程式库之方式,是将下列有 <METADATA> 之标记加到 .asp档案或Global.asa 档案上:
<!--METADATA NAME="Microsoft ActiveX Data Objects 2.5 Library"
TYPE="TypeLib" UUID="{00000205-0000-0010-8000-00AA006D2EA4}"-->
若需有关使用元件类型程式库的详细资料,请参阅之前〈使用变数和常数〉 〈使用常数〉 主题中的。
除了SQL的 INSERT 指令外,您还可使用SQL的 UPDATE 及 DELETE 指令,来变更和移除资料库资讯。
您可使用SQL的 UPDATE 指令来变更资料库表格中项目的值。下列指令使用 UPDATE 指令,将Customers表中,凡LastName栏位为Smith者,皆将其 FirstName栏位的值改成Jeff。
<%
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:
\Data\Employees.mdb"
cnn.Execute "UPDATE Customers SET FirstName = 'Jeff' WHERE LastName
= 'Smith' ",,adCmdText + adExecuteNoRecords
%>
若要从资料库表格中移除特定的记录,请使用SQL之 DELETE 指令。下列的指令会将所有姓氏为Smith的所有列从Customers表格移除。
<%
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:
\Data\Employees.mdb"
cnn.Execute "DELETE FROM Customers WHERE LastName = 'Smith'",,
adCmdText + adExecuteNoRecords
%>
说明
使用SQL之 DELETE 指令时请务必谨慎。 DELETE 若没有跟着 WHERE 子句一起使用,会将表格中所有的列删除。请务必使用SQL 的 WHERE 子句来指定欲删除的列。
使用Recordset物件来处理传回的结果
针对资料之撷取、结果之检验,以及资料库之变更,ADO提供了 Recordset 物件。顾名思义, Recordset 会依照您的查询条件,撷取或显示您所要的资料列或记录。 Recordset 物件会保留每项查询传回之记录所在的位置,便於让您逐项查看结果。
撷取记录集
一个好的Web资料应用程式会同时使用 Connection 物件来建立连结,用 Recordset 物件来运用传回的资料。只要结合这两个物件的特有功能,那麽您几乎能开发所有资料处理类的应用程式。例如,下列伺服器端的指令使用 Recordset 物件来执行SQL之 SELECT 命令。SELECT指令会根据查询条件来撷取特定的资讯集。该项查询尚包含SQL的 WHERE 子句,用来缩小特定条件的查询范围。在这个例子当中, WHERE 子句将查询范围限制在Customers资料库表格中姓氏为Smith的记录。
<%
'与资料来源建立连接。
strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\Data\Employees.mdb"
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open strConnectionString
'为Recordset物件建立例项。
Set rstCustomers = Server.CreateObject("ADODB.Recordset")
'使用Open方法来开启记录集
'并使用Connection物件所建立的连接。
strSQL = "SELECT FirstName, LastName FROM Customers WHERE LastName
= 'Smith' "
rstCustomers.Open strSQL, cnn
'循环查看记录集并显示结果
'并使用MoveNext方法来递增记录的位置。
Set objFirstName = rstCustomers("FirstName")
Set objLastName = rstCustomers("LastName")
Do Until rstCustomers.EOF
Response.Write objFirstName & " " & objLastName & "<BR>"
rstCustomers.MoveNext
Loop
%>
请注意,在刚才的例子中, Connection 物件建立资料库连接,而 Recordset 物件则利用同一个连接,从资料库中撷取结果。如果您想确实了解资料库所建立的连结,那麽这个方法是很有帮助的。比方说,如果您要指定延迟时间之长短,以决定何时终止连接,就要使用 Connection 物件来设定此属性。但如果您只是想用ADO之预设连接属性来建立连接,便可使用 Recordset 物件的 Open 方法来建立连结:
<%
strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\Data\Employees.mdb"
strSQL = "SELECT FirstName, LastName FROM Customers WHERE LastName
= 'Smith' "
Set rstCustomers = Server.CreateObject("ADODB.Recordset")
'使用Open方法来开启连接
'并使用Connection物件建立连接。
rstCustomers.Open strSQL, strConnectionString
'循环查看记录集并显示结果
'并使用MoveNext方法来递增记录的位置。
Set objFirstName = rstCustomers("FirstName")
Set objLastName = rstCustomers("LastName")
Do Until rstCustomers.EOF
Response.Write objFirstName & " " & objLastName & "<BR>"
rstCustomers.MoveNext
Loop
%>
使用 Recordset 物件的 Open 来建立连接,即是间接使用 Connection 物件来巩固该连结。若需其他资讯,请参阅Microsoft Universal Data Access Web网站刊载之Microsoft ActiveX Data Objects(ADO)文件,网址为 http://www.microsoft.com/data/ 。
说明
如果要将ASP资料库应用程式的效能明显提高,可考虑在Application陈述快取记录集。若需其他资讯,请参阅第7章之 〈对资料快 取〉 。
将记录集中传回之记录数量计算出来是很有用的。 Recordset 物件的 Open 方法可让您用选择性的游标(cursor)参数来决定提供者应如何撷取及导览记录集。在陈述式中加上 adOpenKeyset 游标参数来查询,可让用户端应用程式完全导览记录集。因此,应用程式便可运用 RecordCount 属性准确地计算记录集中记录之数量。请看下面的例子:
<%
Set rs = Server.CreateObject("ADODB.Recordset")
rs.Open "SELECT * FROM NewOrders", "Provider=Microsoft.Jet.
OLEDB.3.51;Data Source='C:\CustomerOrders\Orders.mdb'",
adOpenKeyset, adLockOptimistic, adCmdText
'利用Recordset物件的RecordCount属性取得数量。
If rs.RecordCount >= 5 then
Response.Write "We've received the following " & rs.RecordCount
& " new orders<BR>"
Do Until rs.EOF
Response.Write rs("CustomerFirstName")& " " & rs
("CustomerLastName")& "<BR>"
Response.Write rs("AccountNumber")& "<BR>"
Response.Write rs("Quantity")& "<BR>"
Response.Write rs("DeliveryDate")& "<BR><BR>"
rs.MoveNext
Loop
Else
Response.Write "There are less than " & rs.RecordCount & "
new orders."
End If
rs.Close
%>
使用Command物件改善查询
使用ADO的 Command 物件,可执行和 Connection 及 Recordset 物件相同之查询;不同的是,使用 Command 物件时,您可要求查询之资料来源预先作准备或先行编译,日後便可重覆使用不同的值重新发出查询。使用这种经过编译方式来查询的好处是,在修正并重覆现有查询时,可以节省大量的时间。另外,有部分之SQL查询可不用事先定义,只要在执行前再作调整即可。
Command 物件的 Parameters 集合可节省每次查询前再重新建构的麻烦。比方说,如果您要定期更新以Web为基础之库存系统的供应及价格,便可参照下列方式预先定义查询:
<%
'使用Connection物件开启连接。请注意,Command物件
'没有Open方法可建立连接。
strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\Data\Inventory.mdb"
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open strConnectionString
'建立Command物件的例项,使用ActiveConnection属性将
'连接附加到Command物件上。
Set cmn= Server.CreateObject("ADODB.Command")
Set cmn.ActiveConnection = cnn
'定义SQL查询。
cmn.CommandText = "INSERT INTO Inventory(Material, Quantity)
VALUES(?, ?)"
'将CommandText属性中预先准备好(或事先编译好)的查询版本储存起来,
'然後再去执行Command物件。
cmn.Prepared = True
'定义查询参数之组态资讯。
cmn.Parameters.Append cmn.CreateParameter("material_type",
adVarChar, ,255 )
cmn.Parameters.Append cmn.CreateParameter("quantity",adVarChar,
,255 )
'定义并执行首次插入。
cmn("material_type")= "light bulbs"
cmn("quantity")= "40"
cmn.Execute ,,adCmdText + adExecuteNoRecords
'定义并执行第二次插入。
cmn("material_type")= "fuses"
cmn("quantity")= "600"
cmn.Execute ,,adCmdText + adExecuteNoRecords
.
.
.
%>
重要
像 adCmdText 的ADO参数只是一些变数,这表示在资料存取指令中使用ADO参数前必须先定义其值。由於ADO经常使用大量参数,因此用 元件类型程式库 来定义参数会比较简单,让所有ADO之参数及常数定义都包含在该档案内。若需有关执行ADO类型之程式库的详细资料,请参阅之前〈使用变数和常数〉中的 〈使用常数〉 一节。
在刚才的例子当中,您会注意到指令用不同的值反覆建构和重新发出SQL 查询,而没有重新定义,或重新传送查询到资料库来源。使用 Command 物件编译查询的好处是可以避免使用字串和变数来组成SQL查询可能产生的一些问题。尤其在使用 Command 物件的 Parameter 集合时,更可避免因定义某些类型的字串、日期及时间等变数所产生之问题。例如:在SQL查询中若含有上引号('),则会导致查询失败:
strSQL = "INSERT INTO客户(FirstName, LastName)VALUES('Robert', 'O'Hara)"
注意在 O'Hara 这个姓当中含有一个上引号,它和SQL的 VALUES 中用来表示资料之上引号关键字相冲突。如果将该值和 Command 物件参数结合在一起,就可避免这种问题。
结合HTML表单和资料库存取
Web网页上若包含HTML表单,可让使用者远端查询资料库及撷取某些特定资讯。使用ADO,您就能建立非常简单的指令。它能将使用者表单资讯收集起来,建立自订的资料库查询,并将资讯传回给使用者。使用ASP的 Request 物件可撷取在HTML表单中输入的资讯,并在SQL陈述式中使用该资讯。举例来说,下列这段指令将HTML表单所提供的资讯插入表格中,并使用 Request 物件的 Form 集合来收集使用者的资讯。
<%
'使用Connection物件来开启连接。Command物件
'没有Open方法可建立连接。
strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=D:\CompanyCatalog\Seeds.mdb"
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open strConnectionString
'建立Command物件的例项
'并使用ActiveConnection属性将
'连接附加到Command物件上。
Set cmn= Server.CreateObject("ADODB.Command")
Set cmn.ActiveConnection = cnn
'定义SQL查询。
cmn.CommandText = "INSERT INTO MySeedsTable(Type)VALUES(?)"
'定义查询参数之组态资讯。
cmn.Parameters.Append cmn.CreateParameter("type",adVarChar, ,255)
'指定输入值并执行更新。
cmn("type")= Request.Form("SeedType")
cmn.Execute ,,adCmdText + adExecuteNoRecords
%>
若需有关表单及使用ASP之 Request 物件的其他资讯,请参阅之前 〈处理使用者输入〉 一节。
管理资料库连接
要设计出一个巧妙复杂的Web资料库应用程式,例如一个供应数千个客户使用的线上订单输入应用程式,其主要的挑战在於如何适当地管理与资料库间之连接。纵然没有资讯在传递,光是开启及维持与资料库的连结,就会让资料库伺服器的资源产生沉重的负荷,甚至引起连接上的问题。一个设计完善的Web 资料库应用程式,会不断循环资料库之连结,并补偿因网路流量所产生的延迟。
使连接等候逾时
资料库伺服器面临活动激增时,会出现活动滞留之情形,导致建立资料库连接的时间大幅增加。因此,这些延迟会降低资料库应用程式的效能。
若使用 Connection 物件的 ConnectionTimeout ,就能限制应用程式之等候连接时间,并适时放弃连接并发出错误讯息。在下列例子当中,指令将 ConnectionTimeout 属性设定等待二十秒,逾时便取消连接:
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.ConnectionTimeout = 20
cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:
\Data\Inventory.mdb"
ConnectionTimeout 属性的预设值为30秒。
说明
在资料库应用程式中使用 ConnectionTimeout 属性之前,应先确认连接提供者及资料来源支援该属性。
将连接放入集区
将连接放入集区可使Web应用程式从集区使用连接或储备可用的连接,而无需反覆重新建立连接。一旦连接被建立并放置在集区後,应用程式便可重覆使用该连接,而无需再执行连接的程序。如此可大幅增加效能,尤其是那些透过网路连结或需反覆连结、中断连接之应用程式。除此之外,放在集区的连接还可供多个应用程式重覆使用。
OLE DB工作阶段集区
OLE DB也有一个集区功能,称为 工作阶段集区 ,用於在大型的Web资料库应用程式中增进连接的效能。工作阶段集区保留了连接的安全性和其他的属性。唯有连接之双方同时提出要求时,才能重覆使用放在集区中的连结。在预设情况下,Microsoft SQL Server及Oracle的OLE DB提供者皆支援工作阶段集区。这表示您无须自行设定应用程式、伺服器或资料库,就可使用工作阶段集区功能。不过,如果提供者预设不支援工作阶段集区功能,您就需要建立一个登录设定来启用工作阶段集区功能。若需有关工作阶段集区的其他资讯,请参阅OLE DB 2.0 Software Development Kit(SDK)文件。
ODBC连接集区
如果您希望ODBC驱动程式参与连接集区,就必须先设定资料库中特定之驱动程式,然後在Windows登录中设定驱动程式的 CPTimeout 属性。 CPTimeout 属性决定了连接停留在连接集区的时间。如果停留在集区的连接时间超过 CPTimeout 设定的值,那麽连接就会自动关闭,并从集区中移除。 CPTimeout 的预设值为60秒。
针对某些特定的ODBC资料库驱动程式,您可采用下列的设定来建立一登录机码,选择性地设定 CPTimeout 属性来启用连接集区:
\HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\driver-name\CPTimeout
= timeout
(REG_SZ, units are in seconds)
举例来说,下列的机码将SQL Server驱动程式放在集区的时间,设定为 180秒(即3分钟)等候逾时。
\HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\SQL Server\CPTimeout
= 180
说明
根据预设,在您这方的Web伺服器是将 CPTimeout 设为60秒,以便启动SQL Server的连结集区。
在多个网页上使用连接
虽然我们可以将连线储存在ASP的 Application 物件上,以便在多个网页重覆使用连接,可是这些不必要的连接开放情形,会造成连接集区无用武之地。如果您有多位使用者同时连接到同一个ASP资料库应用程式,一个比较好的办法,就是在不同的Web网页上重覆使用资料库连接字串,并将字串放在ASP的 Application 物件内。例如,在Global.asa档案的Application_OnStart事件程序中指定一连接字串,如以下指令所示:
Application("ConnectionString")= "Provider=Microsoft.Jet.OLEDB.4.0;
Data Source=C:\Data\Inventory.mdb"
而在每一个存取资料库的ASP档案中,可以这麽写:
<OBJECT RUNAT=SERVER ID=cnn PROGID="ADODB.Connection"></OBJECT>
如欲建立网页的连接物件例项,请用下列指令来开启连接。
cnn.Open Application("ConnectionString")
在网页末端,可用下列方式来关闭连接:
cnn.Close
万一有个别使用者需要在多个Web网页上重覆使用连接,使用 Session 物件会比用 Application 物件来储存连接字串来得有利。
关闭连接
若要充分利用连接集区,请尽速关闭连接。根据预设,一旦指令结束执行,连接会自动终止。但如果指令在无需使用连接时就关闭连接,可减少资料库伺服器之负荷,并能使连接开放给其他使用者使用。
您可以使用 Connection 物件的 Close 方法将 Connection 物件和资料库间的连接确实关闭。下列指令会开启并关闭一连接:
<%
strConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\Data\Inventory.mdb"
Set cnn = Server.CreateObject("ADODB.Connection")
cnn.Open strConnectionString
cnn.Close
%>
了解异动
企业应用程式经常需要在异动作业中执行指令和元件。 异动 是一种整体成功或失败的伺服器操作,即使操作中包含许多步骤也一样(例如,订货、盘点和帐目作业等)。您可以建立在异动中执行的伺服器端指令,使得任何部分的指令失效时,就会放弃整个异动。
ASP异动处理以「元件服务」异动环境为基础,这是一种用来开发、部署 和管理高性能、可变大小,及大型企业、Internet与intranet伺服器应用程式的异动处理系统。此异动环境定义开发分散式元件应用程式的应用程式设计模型,它还提供有效使用和管理这些应用程式的执行时期环境。
建立异动指令所需的功能内建於Web伺服器中。若有安装元件服务,也可以包裹元件,使它们可以在异动中执行。
关於异动
异动 是一种整体成功或失败的伺服器操作。异动处理可以用於确实地更新资料库。在进行资料库的许多相关变更或同时更新数个资料库时,请确定所有变更都正确地执行。若有任何变更失败,就必须回复资料库表的原始状态。
若无元件服务,就必须撰写指令和元件,以手动方式来追踪要求的变更,以及回复任何变更失败的资料。利用元件服务,就只需要宣告要求异动的指令和元件就可以了,然後让其处理异动的协调工作。异动处理只适用於资料库存取;元件服务无法回溯变更档案系统或其他非异动的资源,而且必须支援应用程式所存取的资料库。目前元件服务支援SQL Server和许多支援X/Open协会XA通讯协定的资料库。
使用 Server.Transfer 和 Server.Execute 方法,异动就可以跨越多个ASP网页。如果指令包含@TRANSACTION语句,并将其值指定为Required,而且该指令由 Server.Transfer 或 Server.Execute 方法来呼叫,则当呼叫 .asp档案有所异动时,该指令仍会继续进行呼叫 .asp档案的异动。如果呼叫 .asp档案并未异动,则呼叫的 .asp档案会自动建立新的异动。
例如,下列指令会起始异动:
<%@ TRANSACTION=Required %> <% . . . '结束异动。 Server.Transfer("/BookSales/EndTrans.asp") %>
不过,下列指令呼叫另一个也会起始异动的指令:
<%@ TRANSACTION=Required%> <% '立即发出自订元件以关闭异动。 Set objSale = Server.CreateObject("SalesTransacted.Complete") . . . %>
不过,这两个指令之间的互动只构成单一异动。若需更多有关使用 Server.Transfer 和 Server.Execute 撰写指令的资讯,请参阅之前
〈传送内容到浏览器〉 一节。
宣告异动指令
在宣告页面可异动时,用於该页面的任何指令命令和物件都在相同的异动内容中执行。元件服务会处理建立异动的细节,并决定异动成功(确定)或失败(放弃)。若要宣告页面可异动,请将 @TRANSACTION语句加入页面上方:
<%@ TRANSACTION = value %>
若需更多有关value引数的资讯,请参阅 @TRANSACTION语句参照。
@TRANSACTION语句必须是页面的第一行,否则就会发生错误。您必须将此语句加入要在异动之下执行的每个页面中。当指令处理完成时,就会结束目前的异动。
多数应用程式只需要特定操作的异动内容。例如,航空公司的站台可以使用异动指令来处理购票和订位工作。所有其他的指令都可在无异动内容之下安全执行。因为异动只能用於需要异动处理的页面,因此您不能宣告应用程式的 Global.asa档案为可异动。
如果放弃异动,元件服务会回溯对支援异动的资源所做的任何变更。目前仅有资料库伺服器完全支援异动,因为这是企业应用程式最重要的资料。元件服务不会回溯硬碟、ASP工作阶段和应用程式变数或集合上的档案变更。不过,您可以依据稍後的叙述来撰写异动事件,以撰写回复变数和集合的指令。如果操作(例如将资料写入档案中)失败,您的指令也可以明确交付或放弃异动。
交付或放弃指令
因为元件服务会追踪异动处理,因此它可判断异动是否已经顺利完成或失败。指令可以呼叫 ObjectContext.SetAbort 而明确宣告放弃异动。例如,如果指令撷取到元件错误、违反企业规则(例如收支馀额低於零)或非异动操作(例如读取或写入档案)失败,则可以放弃异动。如果在完成异动之前页面逾时,也会放弃异动。
撰写异动事件
指令本身无法判断异动已经成功或失败。不过,您可以撰写异动交付或放弃时所呼叫的事件。例如,假设有一个记录银行帐户的指令,并且要视异动状态 将不同的页面传回给使用者。您可以使用 OnTransactionCommit 和 OnTransactionAbort 事件来撰写给使用者的不同回应。
<%@ TRANSACTION=Required %>
<%
'缓冲输出,以显示不同的页面。
Response.Buffer = True
%>
<HTML>
<BODY>
<H1>Welcome to the online banking service</H1>
<%
Set BankAction = Server.CreateObject("MyExample.BankComponent")
BankAction.Deposit(Request("AcctNum"))
%>
<P>Thank you. Your transaction is being processed.</P>
</BODY>
</HTML>
<%
'若异动成功,则显示此页面。
Sub OnTransactionCommit()
%>
<HTML>
<BODY>
Thank you. Your account has been credited.
</BODY>
</HTML>
<%
Response.Flush()
End Sub
%>
<%
'若异动失败,则显示此页面。
Sub OnTransactionAbort()
Response.Clear()
%>
<HTML>
<BODY>
We are unable to complete your transaction.
</BODY>
</HTML>
<%
Response.Flush()
End Sub
%>
在元件服务管理员登录元件
若元件要参与异动,就必须在COM+ 应用程式中登录,而且必须设定为需要异动。例如,如果指令呼叫更新库存资料库和付款资料库的元件来处理订单,就需要这两个元件都在异动内容之下来执行。元件服务可确保有元件失败时,可回溯整个订单而不会更新任一个资料库。有些元件并不需要异动,例如 Ad Rotator元件就不需要异动。
您可以使用「元件服务管理员」来登录和设定异动元件。元件必须登录於 COM+ 应用程式中。请不要将元件放入IIS处理中的COM+应用程式中,而应建立自己的COM+ 应用程式。通常是将您的所有元件放入单一「程式库」应用程式中。程式库应用程式中的元件可供多个ASP应用程式使用,并可在ASP应用程式程序中执行。
您也可以在「伺服器」应用程式中登录异动元件,「伺服器」应用程式是一种在伺服器个别程序中执行的COM+ 应用程式。若要使用角色安全或要从远端电脑的应用程式来存取元件,就可以使用异动元件的「伺服器」应用程式。
您必须安装「元件服务」才能使用「元件服务管理员」。
物件领域
通常是不可以将COM元件所建立的物件存入ASP之 Application 或 Session 物件中。若此,完成异动时会停用COM物件,因为 Session 和 Application 物件是指可跨越多个ASP网页使用的物件例项,不可将它们用来保存异动结束时或释放的物件。
ASP指令是已宣告的异动的根或起始。任何用於可异动ASP网页的COM 物件都可当作异动的一部分。当异动完成时,就会停用页面所用的COM物件,包括储存在 Session 或 Application 物件中的物件。接下来尝试从另一个异动页面呼叫工作阶段领域或应用程式领域物件的动作都会失败。
异动伫列
远端伺服器的资料库更新,可能会因网路延迟或故障而延迟或放弃完成异动。因为异动的各部分都需要确认,您的应用程式可能必须等待远端伺服器的确认或放弃讯息,或因无法传送资料库更新而放弃异动。
对於必须同时完成的更新,适合放弃或延迟完成异动,直到异动的所有参与者都可交付为止。例如,航空公司的订票系统应用程式应该同时完成客户银行帐户的扣款和存入航空公司银行帐户。如果更新整合於异动中,但可能比其他更新还晚发生,最好不要让客户等待完成更新。例如,订购机票的异动可能也会传送特殊餐点要求给餐饮供应商或更新客户的哩程数。这些活动必须完成,但可以稍後才完成。
您可以使用「讯息伫列」将一个更新或一组更新与传送至远端伺服器的异动讯息结合。即使目前无法使用网路,讯息伫列也能保证会将更新传送至远端伺服器。您的应用程式会收到交付讯息,并可继续进行异动。
ASP指令的侦错
无论您的程度有多高,所写的程式或多或少都会有错误,也就是所谓的 臭虫 ,使得伺服器端的指令无法正常执行。因此,寻找指令中的错误并加以更正,也就是俗称的 侦错 (debug)动作,对於开发成功及稳固的ASP软体而言非常重要,当程式的复杂度愈来愈高时,侦错更是不可或缺的要素。
Microsoft Script Debugger工具
Microsoft Script Debugger是一个功能强大的侦错工具,可与Windows Internet Explorer
3.0版以上(含3.0版)搭配,帮助我们找出程式中的错误,并以互动的方式测试伺服器端的指令。Script Debugger的功能包括:
说明
侦错工具可以检视指令以及找出错误,但不能直接修改指令。要修正程式中的错误,请用编辑软体来编辑您的指令并存档,然後再重新执行指令。
启用侦错功能
开始对伺服器端指令侦错前,应该先将Web伺服器设定成支援ASP侦错功能。若需相关的指示与资讯,请参阅第3章之
〈启用ASP侦错功能〉 部分。
在启用Web伺服器的侦错功能之後,就可以利用以下任何一种方法开始对指令进行侦错:
指令错误
对伺服器端指令进行侦错时,可能会碰到好几种错误。其中有些错误会使得指令的执行不正确或导致指令停止执行,有的则会导致程式传回错误的结果。
语法错误
语法 错误是最常见的一种错误,这是由於指令某部分的语法不合乎规定所导致的。例如指令拼错或传给函数的引数个数不对,都会产生错误。语法错误会使得指令无法执行。
执行时期错误
执行时期 错误指的是指令开始执行之後,由於指令做了一些不正确的动作而导致的错误。例如以下这个指令中就有一个函数用0当作除数(在数学上, 0是不可以当作除数的),因此会产生执行时期错误:
<SCRIPT LANGUAGE=VBScript RUNAT=SERVER> Result = Findanswer(15) Document.Write("The answer is " &Result) Function Findanswer(x) '以下这个陈述式会导致执行时期错误。 Findanswer = x/0 End Function </SCRIPT>
导致执行时期错误的臭虫一定要抓出来并加以更正,指令才能正确无误地顺利执行。
逻辑错误
逻辑 错误是最难侦测出来的一种错误。其原因可能是打错字或程式的逻辑上有瑕疵,以致於指令虽然可以从头到尾顺利执行完毕,但得到的结果却是不正确的。例如原本要将一连串数字依大小顺序排序的伺服器端指令,很可能就因为在比较数值的地方把小於(<)符号不小心写成大於(>),於是程式执行完排出来的顺序当然就不正确了。
侦错技巧
以下几种侦错技巧,都可以帮助我们测试应用程式以找出错误的地方。
即时(JIT)侦错
当伺服器端指令遇到执行时期错误而导致不能继续执行时,Microsoft Script Debugger便会自动启动,将此 .asp档显示出来,并在其中标出导致错误的叙述,同时显示错误讯息。此种侦错方式称为 即时 (Just-In-Time, JIT)侦错,可让电脑暂停程式的执行。您必须用编辑软体将错误更正并存档,然後才能继续执行指令。
中断点侦错
当程式有错误产生但又不容易找出真正导致错误的地方时,可以尝试利用设定 中断点 的方式进行侦错。中断点可使得指令执行到您指定的叙述时便暂停执行。您可以在您觉得有问题的叙述之前设定一个或多个中断点,然後用侦错程式检查指令中各项变数或属性的值是否正确。等找出错误并加以更正之後,再将中断点清除,就可以让指令顺利执行了。
设定中断点的方法如下:用Script Debugger开启指令,选取要中断执行的叙述,然後选择 侦错 功能表中的 切换中断点 。接着用Web浏览器再次要求此指令。当指令执行到您设定中断点的这行叙述时,电脑就会启动Script Debugger 显示此指令,并把设定中断点的陈述式标示出来。
在下一个陈述式中断
在某些状况下,如果下一个要执行的陈述式不在您的 .asp档案内时,您可能会想要启用Script Debugger的 在下一个陈述式中断 功能。假设Sales这个程式内有一个 .asp档案,而且您在这个档案内设定 在下一个陈述式中断 ,则当执行Sales中任何一个档案内的指令,或任何一个已经启用侦错的应用程式时,侦错程式便会自动启动。因此当您设定 在下一个陈述式中断 时,应当注意不管接下来执行的是哪一个指令陈述式,只要一执行下去,侦错程式都会自动启动。
利用VBScript的Stop陈述式来侦错
如果您的伺服器端指令是用VBScript设计的,那麽您还可以在怀疑程式中有问题的地方之前,加上 Stop 陈述式来设定中断点。例如以下这个伺服器端指令就含有一个 Stop 陈述式,使得此程式在即将呼叫另一个自订的函数之前暂停执行:
<% intDay = Day(Now()) lngAccount = Request.Form("AccountNumber") dtmExpires = Request.Form("ExpirationDate") strCustomerID = "RETAIL" & intDay & lngAccount & dtmExpires '把中断点设定在这里。 Stop '呼叫注册元件。 RegisterUser(strCustomerID) %>
当您要求这个指令时,侦错程式便会启动,并自动将这个.asp档案显示出来,在其中标示出 Stop 陈述式的位置。在程式把变数传给该元件之前,您应该仔细检查这些变数的值。
重要
在写好的程式要上线之前,请务必记得把其中所有的 Stop陈述式全部拿掉。
利用JScript的Debugger陈述式来侦错
如果您的伺服器端指令是用JScript撰写的,可以在程式中您怀疑的地方之前加上 debugger 陈述式。例如以下这个指令中就含有一个 debugger 陈述式,当回圈每次用新的值执行到这个位置时,程式便会暂停,并自动启动Script Debugger。
<%@ LANGUAGE=JScript %>
<%
for(var count = 1; count <= 10; count++)
{
var eventest = count%2
//在此处设定中断点,让使用者一步一步执行指令。
debugger
if(eventest == 0)
Response.Write("Even value is " + count + "<br>")
}
%>
当您设计的 .asp档案要上线时,请务必记得把程式中的所有 debugger 陈述拿掉。
说明
请勿将 debugger 陈述式与JScript的 break 陈述式混淆。 break 陈述式的目的是从正在执行的回圈中跳出来,并不会启动Microsoft Script Debugger,也不会导致程式暂停执行。
指令侦错秘诀
除了Script Debugger之外,其他还有一些侦错时常运用的秘诀,可以大幅降低您检查指令错误时所花费的时间。虽然大部分的错误都是很明显,一眼就可以辨识出来的,但还是有一些很难找出来的错误,例如拼错指令或变数、某些类型的逻辑错误与执行错误等等。
若需有关Microsoft Script Debugger的其他资讯,请参阅Microsoft Scripting Technologies网站 http://msdn.microsoft.com/scripting/ 。
ASP内建物件
Active Server Pages提供了一些内建的物件,让您更容易收集随着浏览器要求传送过来的资讯、回应资料给浏览器,以及存放与使用者相关的资料,例如使用者选取的个人喜好设定等等。以下就分别简单介绍这些物件。
Application物件
Application 物件可以将资讯开放给应用程式的所有使用者共用。
Request物件
透过 Request 物件可取得随HTTP要求传递过来的所有资讯。包括用POST 方法或GET方法放在HTML表单中传递的参数、cookie,以及用户端的凭证等等。利用 Request 物件还可以取得传给伺服器的二进位资料,例如用户端上传的档案。
Response物件
使用 Response 物件,您可以控制要传给使用者的资讯。包括直接传给浏 览器的资讯、将浏览器导向到另一个URL,以及设定cookie的值。
Server物件
Server 物件可让您存取伺服器上的各种方法与属性,其中以建立COM元件例项的方法( Server.CreateObject )最常被用到。至於其他方法则有其各自的用途,例如对字串作URL或HTML编码、将虚拟路径对应成实体路径,以及设定指令的等候逾时时间等。
Session物件
Session 物件可用来存放特定使用者工作阶段所需的资讯。当使用者在同一个应用程式的各个网页之间跳来跳去时,存放在 Session 物件中的变数并不会消失。换句话说,只要使用者一直存取同一个应用程式的网页,这些变数就会保持存在。利用 Session 方法,还可以直接结束工作阶段,也可以设定闲置工作阶段的等候逾时时间。
ObjectContext物件
ObjectContext 物件可用来交付或中断ASP指令初始的异动。
ASPError物件
利用 ASPError 物件可找出ASP的错误,并传回更详细的说明给使用者。
Active Server Pages物件速查卡
Application物件
集合 :StaticObjectsContents内容集合方法:RemoveRemoveAll 方法 :LockUnlock 事件 :Application_OnEndApplication_OnStart
ObjectContext物件
方法 :SetAbortSetComplete 事件 :OnTransactionAbortOnTransactionCommit
Request物件
集合 :ClientCertificateCookiesFormQueryStringServerVariables 属性 :TotalBytes 方法 :BinaryRead
ASPError物件
属性 :ASPCodeNumberSourceCategoryFileLineColumnDescriptionASPDescription
Response物件
集合 :Cookies 属性 :BufferCacheControlCharsetContentTypeExpiresExpiresAbsoluteIsClientConnectedPICSStatus 方法 :AddHeaderAppendToLogBinaryWriteClearEndFlushRedirectWrite
Server物件
属性 :ScriptTimeout 方法 :CreateObjectExecuteGetLastErrorHTMLEncodeMapPathTransferURLEncode
Session物件
集合 :StaticObjectsContents内容集合方法:RemoveRemoveAll 属性 :CodePageLCIDSessionIDTimeout 方法 :Abandon 事件 :Session_OnEndSession_OnStart