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,毕竟它很简单。
