1. ASP
1.1. 简介
Microsoft® Active Server Pages (ASP) 是服务器端脚本环境,可用来创建交互式 Web 页并建立强大的 Web 应用程序。我们可以采用VBScript和JScript来创建服务器端脚本,也可以内嵌到HTML中,使得编程更为方便,同时可以调用COM组件(如访问数据库的ADO等),这样ASP的功能可以无限地扩增。
服务器上安装IIS后,可以访问http://localhost/iishelp/来访问关于IIS的帮助,其中涵盖了ASP编程指南,所以我们仅对自学难点加以阐述,帮助您达到速成的目的。
(图1.1-1)
ASP不是语言,它是一种环境,具体编程还需要使用VBScript、Jscript等脚本语言。本文示例中除非特殊说明,否则默认采用VBScript。
1.2. 内置对象
尽管在Microsoft提供的资料中会有其他的内置对象,但对于我们来说只要掌握Application、Session、Server、Request和Response五个对象就足够了。学习前,首先对B/S模式作简单介绍,B/S是浏览器(Browser)/服务器(Server)的缩写形式,是一种特殊的客户端(Client)/服务器(Server)模式,客户端主要通过两种方式访问服务器,一种是发送URL地址到服务器,一种是通过已有的HTML页面填写表单提交到服务器;服务器需要做的就是根据得到的客户端信息返回结果—通常就是HTML页面。
如果您做过Socket开发和DLL开发,希望图1.2-1能帮助你了解ASP。
可以不严格的说,ASP中全局内存访问是通过Application对象实现的,服务器资源访问是通过Server对象实现的(Server对象CreateObject方法可以创建COM对象,从而访问更多服务器资源),客户端代理中私有内存通过Session进行管理,接收的数据相对于服务器来说,就是客户端的请求信息(Request对象),发送数据就是服务器对客户端的响应(Response对象实现)。
注意:千万不要总是徘徊在“为什么”中,“到底怎样接收数据”,“到底怎样发送数据”等等,这些过程不需要了解,你可以认为数据就是放在那里的。
1.2.1. Application对象
1.2.1.1. 集合
Application有两个子集合Contents和StaticObjects,一般情况下StaticObjects能实现的事情通过Contents都可以实现,所以我们了解Contents就足够了。
Contents集合中的内容相当于一个语言中的变量名与其值的对应。比如我想记录所有在线人员的个数(UserCount),我们可以这样赋值:
Application.Contents(“UserCount”)=0
或者
Application.Contents(“UserCount”)=Application.Contents(“UserCount”)+1
通常情况下,我们把Application.Contents(…)替换为Application(…),ASP中这是允许的。所以Application.Contents(“UserCount”)将变为Application(“UserCount”)。你可以把Application(“UserCount”)整个部分视为一个变量。
集合Contents有两个方法:Remove及RemoveAll,通过字面即可理解含义,不再赘述。
1.2.1.2. 方法
Lock和Unlock是Application对象提供的两个方法,由于Application使用的是公共的内存,当多个客户端同时访问时就必然会造成冲突,Lock和Unlock就很好的解决了这个问题,写入Application变量前首先调用Application.Lock锁定公共内存,等写入完毕再调用Application.Unlock释放锁定,使你的程序很简单就可以避免多用户访问的问题。
1.2.1.3. 事件
关于Application的事件Application_OnStart及Application_OnEnd请参照Global.asa节有关介绍。
1.2.1.4. 应用
Application对象的内容存放在公共内存区域中,对于所有客户端代理而言皆是完全访问的。公共的事物适合做公共的事情,比如计数器和一些公共对象。
1.2.2. Session对象
1.2.2.1. 集合
Contents和StaticObjects集合是Session中重要组成部分,可以通过调用Session.Contents,来定义Session级的变量,如Session.Contents(“UserLevel”),也可写作Session(“UserLevel”),我们通常也把Session(“UserLevel”)这一部分作为一个变量看待。
其他略。
1.2.2.2. 属性
常用的属性有两个,一个是SessionID,一个是Timeout。
SessionID在一次Web服务运行周期内,唯一标识一个客户端。需要注意的是“一次服务运行周期”,如果重起Web服务,SessionID将极大可能与重起前某次的SessionID相同,所以千万不要用SessionID作为数据库表中主关键字。
Timeout表示在客户端多长时间没有刷新或发送请求后,服务器将认为其Session已结束,单位为“分钟”,IIS5.0中默认为10分钟。Session.Timeout时间后,将触发Session_OnEnd事件。设置此属性的根本原因是由于http协议造成的,每次浏览器向服务器发送请求后,就立即断开,但服务器需要在一定时间内保留客户端的连接信息,如果用户超过一定时间(Timeout的值)没有刷新,发送请求或者直接关闭了浏览器,服务器需要把这个客户端的Session信息删除。想象一下,如果Session信息用不删除,服务器终究会内存不足,然后造成系统崩溃。这也是DoS攻击的简单原理。所以,Timeout属性值的大小必须根据实际情况设置合适的值。
1.2.2.3. 方法
如果说设置Session.Timeout是为了被动的删除没有用的客户端信息,Session.Abandon就是主动删除没有用的客户端信息,且将主动触发Session_OnEnd事件。在Internet中,用您自己的账号登录一个网站后,通常会有“退出登录”的功能,而且网站一般都建议您通过点击“退出登录”来退出而不是简单的关闭浏览器。“退出登录”通常的实现就是删除当前账号的登录信息(可能包含数据库中的信息或者存储文件中的信息),以防被人盗用。
1.2.2.4. 事件
Session_OnStart和Session_OnEnd事件参见Global.asa节。
1.2.2.5. 应用
Session的特点就是私有性,所以开发者通常用来存放登录用户的私有信息,如权限、级别等信息。
1.2.3. Server对象
1.2.3.1. 属性
Server对象仅有一个属性ScriptTimeout,用来设置脚本的最长运行时间,否则将被中断。设置单位为秒,默认值为90秒。
Server.ScriptTimeout与IIS管理对象中的元数据(Metabase)相互影响,其时间值将取两者之间的最大值。
1.2.3.2. 方法
关于Execute和GetLastError方法请查阅相关资料。
1.2.3.2.1. CreateObject
ASP对于服务器的访问能力几乎全部从Server.CreateObject扩展,如对目录文件系统的访问,可以创建Scripting.FileSystemObject对象,如数据库连接可以创建ADODB.Connection对象等等。当然您也可以开发自己的COM对象,比如加密、文件上载,或者隐藏的业务逻辑等等。
服务器组件中如果包含OnStartPage和OnEndPage的实现,那么创建服务器组件时OnStartPage将被执行。
例如,创建文件系统对象FileSystemObject:
Set fso = Server.CreateObject("Scripting.FileSystemObject")
‘然后就可以调用Com的任何方法或属性了:
Set MyFile = fso.CreateTextFile("c:\testfile.txt", True)
MyFile.WriteLine("This is a test.")
MyFile.Close
Set MyFile = Nothing
Set fso = Nothing
现在,查看一下服务器的C盘根目录下是否多了一个testfile.txt文件,打开后的文件内容见图1.2.3.2.1-1:
1.2.3.2.2. HTMLEncode
HTMLEncode对给定的字符串进行HTML编码,通常是结合Response对象使用。如果需要显示HTML中的特殊字符,就需要进行编码,比如“<”编码为“<”,空格符“ ”编码为“ ”等等。
例如:
<%=Server.HTMLEncode("The paragraph tag: <P>") %>
输出结果为:
The paragraph tag: <P>
浏览器解释处理后,显示::
The paragraph tag: <P>
1.2.3.2.3. MapPath
MapPath方法主要用来把服务器上的相对路径或虚拟路径转化为绝对路径。
调用方法:Server.MapPath(path)。
如果path中以“/”或“\”开始,则将path作为虚拟路径的全路径取结果返回。
1.2.3.2.4. Transfer
Session.Transfer将把当前ASP文件已经装配的信息发送到另外的ASP中,并将结果组合输出。
例如test.asp内容为:
<HTML><BODY><%
Dim sessvar1
Response.Write Session.SessionID
Response.Write ("<BR>")
Response.Write ("I am going to ASP2 <BR>")
Server.Transfer("test2.asp")
%>
Test2.asp的内容为:
<% Response.Write Session.SessionID %></BODY></HTML>
以上代码中Response.Write为发送信息到浏览器,请查阅Response对象相关描述。通过URL访问test.asp,将组合以下结果(鼠标右键单击浏览器,然后查看源代码):
<HTML><BODY>214636745<BR>I am going to ASP2
<BR>214636745</BODY></HTML>
在浏览器中显示如图1.2.3.2.4-1所示:
(图1.2.3.2.4-1)
1.2.3.2.5. URLEncode
Server.URLEncode可以对一个字符串进行URL编码,通常情况下我们用来组合一个链接,转换其中的特殊字符(比如空格、汉字等)。
1.2.3.3. 应用
关于服务器资源的访问,使用Server是当仁不让。通过开发COM,通过Server.CreateObject调用,既掩盖了业务逻辑,又充分发挥ASP环境的优势。
1.2.4. Request对象
1.2.4.1. 集合
1.2.4.1.1. Cookies
如果对Web有所了解,就应该知道,在客户端如果没有特殊的ActiveX支持的话,客户端的脚本不可能访问客户端资源。有些时候,我们希望用户登录一个网站后就记录某些信息,比如以什么账号登录的,在关闭再打开浏览器后,这些信息依然存在,并且不需要再次登录。这个时候可以利用浏览器管理的Cookies来简单实现。
Cookies的资源空间很小,所以不可能把所有信息都存放到Cookies中,并且由于存放于客户端,还会涉及到安全性的若干问题。
Request.Cookies(key)可以返回关于key的值,或者是一个字典(dictionary),如果需要判断它返回的是值还是字典,可以通过调用Request.Cookies(key).HasKeys的返回值来判断,True表示为字典,False表示为值。
<%=Request.Cookies("myCookie").HasKeys %>
1.2.4.1.2. Form
我们知道在HTML的标记中就有<form>标记,通常我们会看到这样的HTML代码:
<form method=”POST” action=”dologin.asp”>
<p align=”center”>账号:<input type=”text” name=”LoginUser” /></p>
<p align=”center”>口令:<input type=”password” name=”LoginPWD” /></p>
<p align=”center”><input type=”submit” value=”提交”/> <input type=”reset” value=”重写” /></p>
</form>
在网页上显示需要我们输入账号与密码,然后点击“提交”按钮就会把数据提交到dologin.asp处理,这个时候dologin.asp中就可以通过调用Request.Form(“LoginUser”)与Request.Form(“LoginPWD”)来得到客户端用户输入的相应账号与口令。
您好,<%=Request.Form("LoginUser") %>,<br>
您输入的口令为:<%= Request.Form("LoginPWD") %>。<br>
但是并非所有的<form>标记提交到服务器的都可以用Request.Form来得到相应的值,这还需要看<form>标记中method的值是否是”POST”,如果是则可以,否则不行。比如,method的值为”GET”,则等同于通过URL编码来请求服务器页面;假设在账号只能中输入了“test”,口令中输入了“123”,则URL将为:
http://localhost/dologin.asp?LoginUser=test&LoginPWD=123
这个是否,服务器中则需要通过Request.QueryString来获取相应LoginUser与LoginPWD的值了。
1.2.4.1.3. QueryString
Request.QueryString同Request.Form类似,如上节所述,如果<form>标记中method的值为”GET”或者通过地址来输入URL,则用Request.QueryString来得到相应值。
URL中ASP脚本“?”后面部分为通过URL传递的数据部分,以符号“&”来分隔,每一部分钟中,等号前面可以成为关键字(Key),等号后面的部分为相应的值,很多情况下,值这一部分是经过Server.URLEncode编码后的,Request.QueryString得到相应的值时就已经自动解码了,所以Server对象中根本不需要提供解码函数。
比如上节中的URL,对应dologin.asp应该这样实现:
您好,<%=Request.QueryString("LoginUser") %>,<br>
您输入的口令为:<%= Request.QueryString("LoginPWD") %>。<br>
1.2.4.1.4. ServerVariables
ServerVariables集合用来返回所有已确定的环境变量的值。这些都是跟这次客户端连接相关的变量。比如Request.ServerVariables(“LOCAL_ADDR”)返回服务器IP地址;Request.ServerVariables(“REMOTE_ADDR”)客户端IP地址等等。详细的列表说明请查看“http://localhost/iishelp/iis/htm/asp/vbob5vsj.htm”。
1.2.4.2. 属性
1.2.4.2.1. TotalBytes
TotalBytes返回客户端发送的请求主体的字节数。
通常情况下,TotalBytes属性跟Request.BinaryRead方法结合使用,以得到客户端发送来的二进制数据流。
1.2.4.3. 方法
1.2.4.3.1. BinaryRead
BinaryRead方法用来得到客户端通过POST方法提交到服务器的数据,然后存放到SafeArray中。SafeArray是包含维数及范围的数组。
注意,一旦您使用了BinaryRead方法,再使用Request.Form来获取相应关键字变量的值就会出错,Request.BinaryRead的使用方法如下:
<%
Dim vntPostedData, lngCount
lngCount = Request.TotalBytes
vntPostedData = Request.BinaryRead(lngCount)
%>
1.2.4.4. 应用
通过访问Request对象,您可以得到客户端代理得到客户端的所有信息。
1.2.5. Response对象
1.2.6. 集合
1.2.6.1. Cookies
Response.Cookies用来向客户端设置相应的Cookie,设置方法为:
<% Response.Cookies("myCookie") = "Hello World!" %>
1.2.7. 属性
1.2.7.1. Buffer
Response.Buffer用来标识向客户端发送的内容是否缓存,False为不缓存,True为缓存。IIS4.0及以下版本默认为False,IIS5中默认为True。
当Response.Buffer设置为缓存时,输出内容一直等到整个ASP页处理完毕,或者调用了Response.Flush或Response.End方法后才发送至客户端。
1.2.7.2. Charset
Response.Charset用来向返回内容的头部添加字符集信息,例如简体中文字符集“GB2312”。
<% Response.Charset= "GB2312" %>
1.2.7.3. ContentType
Response.ContentType用来指出返回客户端的内容类型,例如HTML类型“text/html”,纯文本类型“text/plain”,JPEG图片类型“image/JPEG”等等。
<% Response.ContentType = "image/JPEG" %>
1.2.7.4. Expires
Response.Expires指出当前网页经过多少时间后网页过期,单位“分钟”。IIS会根据给出的过期数值添加到HTTP头中。但由于服务器时间与客户端时间的不一致,例如时区的原因,或者哪个出了问题,设置Response.Expires=0,将不会达到网页立即过期的效果,相反您可以通过设置Response.ExpireAbsolute来达到立即过期的目的。更好的方式是设置Response.Expires为一个负数,例如:
<% Response.Expires=-1 %>
也可使网页立即过期。
1.2.7.5. ExpiresAbsolute
Response.ExpiresAbsolute通过设置具体的日期和时间来达到过期的效果。如果仅指定日期而没有指示时间,网页将在指定日期的午夜12:00过期;如果仅指定时间而不指定日期,网页将在脚本运行的当天那个时间过期。
<% Response.ExpiresAbsolute=#May 31,2004 11:11:11# %>
上例将使网页在2004年5月31日11点11分11秒过期。
1.2.8. 方法
1.2.8.1. AddHeader
AddHeader方法可以在发送的HTTP数据中添加相应的头信息。
下例将强迫客户端使用基本验证方式:
<% Response.Addheader "WWW-Authenticate", "BASIC" %>
1.2.8.2. BinaryWrite
Response.BinaryWrite将通过HTTP向客户端发送二进制流。我们时常用它来提供软件下载,组合图片显示等。
1.2.8.3. Clear
当Response.Buffer=True时,通过调用Response.Clear可以清除发送缓冲区中的所有内容。当Response.Buffer设置为False时,调用Response.Clear将出现错误。
1.2.8.4. End
通过调用Response.End可以终止当前服务器脚本的执行,并将结果发送客户端。
1.2.8.5. Flush
Response.Flush将在Reponse.Buffer为True时发送缓冲区中的数据。如果Response.Buffer=False,调用Reponse.Flush将出错。
1.2.8.6. Redirect
调用Reponse.Redirect将跳转至另外的URL地址。如果已经发送HTML信息到客户端,调用此方法将出现错误。下例将跳转至“CSDN”:
<% Response.Redirect “http://www.csdn.net” %>
1.2.8.7. Write
Response.Write方法将发送指定字符串到客户端。
<% Response.Write “Hello World!” %>
1.2.9. 应用
Reponse对象就是用来向客户端发送信息的,它不仅可以发送一般的HTML信息,同样,通过指定HTTP头,或者设置Response.ContentType属性,然后调用Response.BinaryWrite方法返回任何形式的内容,图片、各种文档等等。所以我们可以实现计数器、文件下载等,然后稍加结合我们还可以实现文件下载并计数,只有你想不到的,没有你做不到的。
1.3. Global.asa文件
我们仅对Application和Session相应事件加以描述。
1.3.1. Application事件
1.3.1.1. Application_OnStart
当启动Web服务后,第一个客户端通过浏览器访问您的网站时,将首先触发Application_OnStart事件,因为这个时候可能需要您在公共内存区域中预先定义一些Application变量,或者预先访问一些服务器资源。
<SCRIPT LANGUAGE=ScriptLanguage RUNAT=Server>
Sub Application_OnStart
. . .
End Sub
</SCRIPT>
1.3.1.2. Application_OnEnd
由于您在Application_OnStart很有可能就声明了Application变量来存储COM对象等等,如同面向对象的编程一样,您的网站的析构函数就是Application_OnEnd。当所有客户端断开连接并会话结束,将触发Application_OnEnd。
<SCRIPT LANGUAGE=ScriptLanguage RUNAT=Server>
Sub Application_OnEnd
. . .
End Sub
</SCRIPT>
1.3.2. Session事件
1.3.2.1. Session_OnStart
当客户端连接上服务器时,服务器端必然需要创建新的客户端代理来响应客户端请求,创建新的客户端代理后就会触发Session_OnStart事件。
<SCRIPT LANGUAGE=ScriptLanguage RUNAT=Server>
Sub Session_OnStart
. . .
End Sub
</SCRIPT>
1.3.2.2. Session_OnEnd
当客户端调用的服务器脚本中显式地调用了Session.Abandon方法或者客户端超过了Session.Timeout的时间被动的会话终止,在会话终止前Session_OnEnd将被触发。
<SCRIPT LANGUAGE=ScriptLanguage RUNAT=Server>
Sub Session_OnEnd
. . .
End Sub
</SCRIPT>
1.3.3. 应用
根据Application与Session事件的特点,我们可以初始化全局公共的Application变量,或者仅当前客户端的私有环境变量。比如,我们可以通过一个Application变量Application(“ClientCount”)来记录连接到服务器的客户端总数,然后,每次Session_OnStart时,Application(“ClientCount”)增加一个,Session_OnEnd时,Application(“ClientCount”)减1,这样就可以比较准确的记录客户端总数。
<Script Language=VBScript RUNAT=Server>
Sub Application_OnStart
Application(“ClientCount”)=0
‘其他代码
End Sub
Sub Application_OnEnd
Application(“ClientCount”)=0 ‘仅为示范用,表示复原之意
‘其他代码
End Sub
Sub Session_OnStart
Application.Lock
Application(“ClientCount”)=Application(“ClientCount”)+1
Application.UnLock
End Sub
Sub Session_OnEnd
Application.Lock
Application(“ClientCount”)=Application(“ClientCount”)-1
Application.UnLock
End Sub
</Script>
是的,就这么简单。
1.4. 关于COM的简单说明
由于ASP的功能主要通过COM来扩展,我们只好再啰嗦几句,通过FSO的对象,可以实现基本的文件访问;通过创建ADO我们可以访问各式各样的数据库;通过MSXML我们实现XML的各种操作。它们的详细帮助说明都包含各自得SDK中,MSDN也可以找到。
一个网站,关键在于您想怎么实现,思路很重要,剩余的就慢慢查阅资料吧。比如您可以创建一个XML架构的网站,通过组织数据为自定义的XML格式,然后以不同XSL实现不同的用户客户端,既可起到模版的作用,又可实现数据的过滤(不需要的东西,通过XSL的处理将不发送到客户端)。关于最新的MSXML,请到微软的站点下载。
1.5. 关于.Net
自从有了.Net以后,学习新语言的浪潮可谓一浪高过一浪,然而在应用一门新的语言前,人们首先应该强调的是语言的熟悉程度,发挥不了新语言的特长就没有必要采用新的语言。
ASP.Net环境也是如此,如果您对DHTML、CSS、HTC、ASP、XML等等都非常熟悉,那么学习ASP.Net也会轻车熟路。不妨先学习学习ASP,毕竟它很简单。