集合
当用户填写页面<FORM>内容时所提供的全部值,或在浏览器地址栏输入在URL后的值,通过Form和QueryString集合为ASP脚本所用。这是在ASP代码中访问值的一种简单方法。
1、 访问ASP集合的一般技术
大多数ASP集合与在VB中见到的普通集合相差不多。实际上,它们是值的数组,但能通过使用一个文本字符串键(对大小不敏感)以及一个整型索引进行访问。因此,假如客户端Web页面包含的<FORM>如下:
<FORM ACTION=”show_request.asp” METHOD=”POST”>
FirstName:<INPUT TYPE=”TEXT” NAME=”FirstName”>
LastName:<INPUT TYPE=”TEXT” NAME=”LastName”>
<INPUT TYPE=”SUBMIT” VALUE=”Send”>
</FORM>
可通过访问ASP的Form集合来访问其控件内的值:
strFirstName = Request.Form(“FirstName”)
strLastName = Request.Form(“LastName”)
也可使用窗体中控件的整型索引,索引的范围从在HTML中第一个定义的控件开始,然后根据定义的顺序排序:
strFirstName = Request.Form(1)
strLastName = Request.Form(2)
然而,后面的这种以整型为索引的技术不推荐使用,因为一旦有HTML中的控件发生了变化,或者插入一个新的控件,则ASP代码将得到错误的值。进一步而言,对于阅读代码的人来讲,极容易混淆。
1) 访问集合的全部值
可以通过引用集合把整个Form上的一系列值变成单个的字符变量,且不用提供键或索引。
StrAllFormContent = Request.Form
假如文本框包含值Priscilla和Descartes,则Request.Form语句将返回下列字符:
FirstName=Priscilla&LastName=Descartes
注意,提供的值是以名称/值对的形式出现的(即控件名称=控件值),并且每一对名称/值相互之间是用符号“&”相分隔的。假如打算把窗体中的内容传递单独的,希望得到值的标准格式的可执行应用程序或DLL,这个技术是很有用的。然而,一般说来,都是通过以窗体中控件的名称为文本键来访问集合中的内容。
2) 遍历一个ASP集合
有两种方式遍历一个ASP集合中的所有成员,方式与普通VB集合的基本相同。每个集合提供一个Count属性,返回的是集合中条目数量。可通过使用一个整型索引使用Count属性来遍历。
For intLoop=1 To Request.Form.Count
Response.Write Request.Form(intLoop) & “
”
Next
假如先前的窗体包含Priscilla和Descartes值的两个文本框,将得到如下结果:
Priscilla
Descartes
然而,更好的方法是使用For Each...Next结构。
For Each objItem In Request.Form
Response.Write objItem & “=” & Request.Form(objItem) & “
”
Next
这带来的好处是既可以访问控件的名称又可访问其值。上述代码将得到如下结果:
FirstName = Priscilla
LastName = Descartes
注意,一些浏览器返回到ASP的<FORM>值可能与页面上显示的顺序不尽相同。
3) 集合成员的多值性
在某些情况下,ASP集合中的各个成员可能不止一个值,这种情况发生在HTML定义中有几个控件有相同Name属性时。例如:
<FORM ACTION=”Show_request.asp” METHOD=”POST”>
<INPUT TYPE=”TEXT” NAME=”OtherHobby”>
<INPUT TYPE=”TEXT” NAME=”OtherHobby”>
<INPUT TYPE=”TEXT” NAME=”OtherHobby”>
<INPUT TYPE=”SUBMIT” VALUE=”Send”>
</FORM>
在Form集合中,将为“OtherHobby”创建一个条目。然而,它将包括从三个文本框中得到的值。假如在提交时,用户留下了一个或多个为空,则返回的值为空字符串。假如用户在第一和第三个文本框分别输入Gardening和Mountaineering,第二个文本框为空,在我们的ASP代码中访问Request.Form(“OtherHobby”),将返回字符串:
Gardening, ,Mountaineering
为了能够在这种情况下,访问单个值,可以用复杂一些的代码:
For Each objItem In Request.Form
If Request.Form(objItem).Count >1 Then ‘More than one value in this item
Response.Write objItem & “:
”
For intLoop = 1 To Request.Form(objItem).Count
Response.Write “Subkey” & intLoop & “value = “_
& Request.Form(objItem) (intLoop) & “
”
Next
Else
Response.Write objItem & “ = ” & Request.Form(objItem) & “
”
End If
Next
对于前面的包含三个OtherHobby控件的窗体实例,这将返回:
OtherHobby:
Subkey 1 value = Gardening
Subkey 2 value =
Subkey 3 value = Mountaineering
然而,由于很少给多个文本框相同的名字,因此这种技术很少用到。
a) HTML中的单选或选页按钮控件
在HTML中,需要给几个控件相同的Name属性的情况是单选(或选项)按钮,例如:
<FORM ACTION=”show_request.asp” METHOD=”POST”>
I live in:
<INPUT TYPE=”RADIO” NAME=”Country” VALUE=”AM”>America
<INPUT TYPE=”RADIO” NAME=”Country” VALUE=”EU”>Europe
<INPUT TYPE=”RADIO” NAME=”Country” VALUE=”AS”>Asia
<INPUT TYPE=”SUBMIT” VALUE=”Send”>
</FORM>
因为用户只能选择多项中的一个(这就是给它们相同的名字的原因),将仅得到一个返回值,浏览器只能发送所选择控件的值。因此,假如这个窗体的用户已经选择了“Europez”,将得到这个条目,通过遍历Form集得到其值:
Country = EU
由于为每个控件提供了不同的VALUE属性,反映了每个条目所对应的国家或地区的名称。假如省略了VALUE属性,浏览器将返回的值为“on”,因此将得到:
Country = on
这是不经常用到的,因此一般对使用相同名称的单选控件使用VALUE属性。
b) HTML复选框控件
当一个窗体中HTML源码包含一个复选框控件时,一般都给定唯一的名称,例如:
<FORM ACTION=”show_request.asp” METHOD=”POST”>
I enjoy:
<INPUT TYPE=”CHECKBOX” NAME=”Reading” CHECKED> Reading
<INPUT TYPE=”CHECKBOX” NAME=”Eating”> Eating
<INPUT TYPE=”CHECKBOX” NAME=”Sleeping”> Sleeping
<INPUT TYPE=”SUBMIT” VALUE=”Send”>
</FORM>
在这种情况下,提交窗体时,假如仅是第一和第三个复选框被选中(加标记),遍历Form集合时,会得到下列值:
Reading = on
Sleeping = on
然而,假如为每个复选框提供一个值,把这个值发往服务器代替字符串“on”。例如窗体如下:
如果除第三个复选框外,全部提交,在Request.Form集合会产生下列结果:
Hobby = Hobby025, Hobby003, Hobby010
假如编写更复杂一些集合遍历代码,如先前所述(单独显示每个子键),就得到这样结果:
需要注意的是两种情况,没有选中的控件根本不返回任何值。在第一种情况的结果里,没有欺骗性的逗号,第二种情况也没有空值。这与上述的使用文本框的相当的测试的结果不一样。使用文本框时,每个文本框都返回一个值,即使是一个空字符串。这是浏览器造成这样的结果。因此在ASP代码中访问集合时,要注意这个问题。
上述情况一个棘手的负作用是使用复选框时,复选框值的索引与在原始的HTML中控件的位置没有任何联系,在上述的例子中第四个复选框的子键数为3,因为当窗体提交时,第二个控件没有选中。
c) HTML列表控件
HTML中的<SELECT>标记用来产生标准的下拉列表框,其值以一种有趣的混合方式表示。下列的窗体创建了包含5个值可供用户选择,由于包含了MULTIPLE属性,因此可以通过选择时按下Shift或Ctrl键,选择不仅一个的条目。
下图所示为该页面,显示的是选中了三个条目。
这种特殊的情况返回的是在Form集合中单个条目,它包含选择的值(单个的<OPTION>标记中指定的VALUE属性),用逗号分隔:
假如使用更加复杂一些的集合遍历代码(单独显示每个子键),将得到:
Hobby:
Subkey 1 value = Hobby025
Subkey 2 value = Hobby003
Subkey 3 value = Hobby010
这与上述相同名称的复选框的情况相同。事实上可以认为一个SELECT列表是一列复选框的列表供选择(不是选中)相应的条目。
然而,列表框也有指定的值,假如在<OPTION>标记中设置VALUE属性,将得到的是选择的选项的文本内容,Request.Form集将包含这样一个项目:
Hobby = Swimming, Reading, Sleeping
并且,同样,复杂一些的集合遍历代码将返回如下结果:
Hobby:
Subkey 1 value = Swimming
Subkey 2 value = Reading
Subkey 3 value = Sleeping
当然,假如单个项目被选择,且在<OPTION>中提供了VALUE属性,得到结果包含的仅是:
Hobby = Hobby025
如果没有提供VALUE属性,得到:
Hobby = Swimming
这允许既可以缺省(即无VALUE)显示选项文本,也可做相应的改变。后一种情况在某些情况下是极为有用的,如要显示(一个说明的字符串)和传递一个完全不同的内容(如用一个短码代表一个说明性的字符串)。
d) HTML提交和图像控件
复选框和单选框是布尔型控件的例子,选中或选择返回的为“on”,不像文本框和大多数其他的HTML控件,浏览器不包含没有选中或没有选择的控件的值。
还有另外一种常用的布尔型控件,称为HTML按钮。如<INPUT TYPE=”SUBMIT”>、<INPUT TYPE=”RESET”>、<INPUT TYPE=”IMAGE”>、<INPUT TYPE=”BUTTON”>和<BUTTON>...</BUTTON>类型。
BUTTON类型的控件不返回任何值,因其对窗体没有直接的影响。即使使用用来调用窗体的Submit方法,浏览器在任何请求中将不包含BUTTON类型控件的值。同样,一个<INPUT TYPE=”RESET”>按钮的值也决不会发往服务器。
然而,输入按钮控件SUBMIT和IMAGE类型实际提交窗体给服务器,其VALUE属性包含窗体的其他控件的值(只要在HTML定义中包含一个NAME属性)。例如,这个窗体可能是向导类型Web应用程序的一部分,允许用户一步步进行或取消进程:
<FORM ACTION=”show_request.asp” METHOD=”POST”>
<INPUT TYPE=”SUBMIT” NAME=”btnSubmit” VALUE=”Next”>
<INPUT TYPE=”SUBMIT” NAME=”btnSubmit” VALUE=”Previous”>
<INPUT TYPE=”SUBIMT” NAME=”btnSubmit” VALUE=”Cancel”>
</FORM>
在一个窗体中,可以包括多个SUBMIT按钮。在这种情况下,应该给每一个按钮唯一的VALUE属性,如上所示。当一个窗体被提交时,遍历Request.Form集合的值,将产生一个值,这个值依赖于按下哪个按钮用于提交这个窗体。假如用户按下的“Previous”按钮,将得到:
btnSubmit = Previous
因此,可查询Request.Form集合来决定下一个显示的页面,例如:
Select Case Request.Form(“btnSubmit”)
Case “Next”
Response.Redirect “page_3.asp”
Case “Previous”
Response.Redirect “page_1.asp”
Case “Cancel”
Response.Redirect “main_menu.asp”
End Select
同时,也可根据需要对每个按钮使用不同的NAME属性。且选择其值包含在Form集合中的控件名称。在控件没有一个完整的标记而是随后跟着较长的文本标签的情况下,极为有用,如下图所示。
此屏幕上的界面由下列代码产生:
<FORM ACTION=”show_request.asp” METHOD=”POST”>
<B>What do you want to do now?</B><P>
<INPUT TYPE=”SUBMIT” NAME=”btnNext” VALUE= ”> Go on the next page<P>
<INPUT TYPE=”SUBMIT” NAME=”btnPrevious” Value=” ”> GO back to the previous page<P>
<INPUT TYPE=”SUBMIT” NAME=”btnCancel” VALUE=” ”> Cancel and go back to the main menu page<P>
</FORM>
在ASP页面中,接收到数据后,可以检查按扭名称提供的值来判断按下的是哪个按钮。
If Len(Request.Form(“btnNext”)) Then Response.Redirect “page_3.asp”
If Len(Request.Form(“btnPrevious”)) Then Response.Redirect “page_1.asp”
If Len(Request.Form(“btnCancel”)) Then Response.Redirect “main_menu.asp”
这个工作是查询一个键上的ASP集合,如果不存在则返回一个空的字符串。换句话说,如果第二个按钮(previous页)按下,则Request.Form(“btnNext”)的值是一个空字符串,则其长度为零而不至于产生一个错误。当第二个按钮按下时,则在Form集合中这个条目的值Request.Form(“btnPrevious”),将是“ ”其长度大于零。
e) 提高使用Request集合的效率
访问一个ASP集合来下载一个值是费时的需计算资源的过程,因为这个操作包含了一系列对相关集合的搜索,这比访问一个局部变量要慢得多。因此,如果打算在页面中多次使用集合中的一个值,应该考虑将其存贮成为一个局部变量,例如:
strTitle = Request.Form(“Title”)
strFirstName = Request.Form(“FirstName”)
strLastName = Request.Form(“LastName”)
If Len(stTitle) Then strTitle = strTitle & “ “
If strFirstName = “ “ Then
StrFullName = strTitle & “ “ & strLastName
ElseIf Len(strFirstName) = 1 Then
StrFullName = strTitle & strFirstName & “· “ & strLastName
Else
StrFullName = strTitle & strFirstName & “ ” & strLastName
End If
f) 搜索所有的Request集合
在某些情况下,可能知道一个值的键名将出现在Request集合中,但不能准确地知道是哪一个集合。例如,假如有几个页面(或一个页面的不同段)发送一个值给同一个ASP脚本,它可能在Form或者QueryString集合中出现。
本章后面部分将研究Form和QueryString集合的差异。
要看一下一个值为什么可能出现在不同的集合中,考虑一下这种情况:使用了<A>超级链接元素请求一个页面。在这种情况下,增加一个值到请求的唯一方法是把它加到URL上。然而,同样的值可能已出现在另一个页面的<FORM>中,或同一页面不同部分:
...
<FORM ACTION=”process_page.asp” METHOD=”POST”>
<INPUT TYPE=”SUBMIT” NAME=”page” VALUE=”Next”>
<INPUT TYPE=”SUBMIT” NAME=”page” VALUE=”Previous”>
<INPUT TYPE=”SUBMIT” NAME=”page” VALUE=”Help”>
</FORM>
...
...
For help go to the <A HREF=”process_page.asp?page=Help”>Help Page</A>
...
在这种情况下,按下窗体上的Help按钮,将发送Request.Form集合中一对名称/值“page=Help”。然而,按下<A>超级链接也可能发送名称/值“Page=Help”,但是这次却是在QueryString集合里。为访问这个值,可使用ASP Request对象的一个特殊功能:
strPage = Request(“page”)
这将按序搜索全部的集合——QueryString、Form、Cookies、ClientCertificate、ServerVariables,直到发现第一个匹配值的名称。这样做比直接访问适当的集合效率低,并且是不安全的,除非能绝对保证这个值不会出现在另外一个集合中。
例如,可能希望搜集满足客户请求的Web服务器的名称,这通过出现在每个查询中的Request.ServerVariables集合中寻找“SERVER_NAME”来实现。然而,假如任一其他的集合也包含名为“server_name”的值(记住键名不区分大小写),当使用Request(“server_name”)时,得到的是错误的结果。使用Reqeust.ServerVariables(“server_name”)句法,我们将很难进行错误追踪。
总而言之,使用“搜索全部集合”技术要格外小心,且只在没有其他技术能够提供你需要的结果时使用。
g) 访问其他的集合
本章的这一节里,已经集中讨论了Form集合,这可能是使用得最多的一个。然而,所有这些技术同样适用于其他的对象。包括那些由Request对象提供的(即Form、QueryString、Cookies、ServerVariables和ClientCertificate)集合,及由Response对象提供的cookies(及将在下两章遇到的其他对象提供的集合)。
我们将简短了解一个值如何进入一个QueryString集合,及其优点和不足。然而,同时这两个Cookies集合有额外的功能,可以使使用cookie更加方便,下面讨论这个内容。
访问和更新Cookies集合
Cookies的值比ASP其他集合(例如Form和ServerVariables)的值要复杂得多。Cookie是一小块由浏览器存贮在客户端系统上的文本,且随同每次请求发往它们应用于的域中的服务器。
ASP使得应用cookie较为容易,可以从Request对象的Cookies集合中获得所有随同请求发出的cookie值,并可创建或修改cookie,通过Response对象的Cookies集合发回给用户。
Cookie包含可用两种方式构造的信息,单值cookie提供其值给代码是通过一个一般的类ASP集合。然而,集合的每个成员可能本身也是一个集合,包含这种信息的cookie通过称为多值(multiple-Value)cookie。
创建一个单值的cookie较为简单,如下所示:
Response.Cookies(“item-name”) = “item-value”
创建一个多值的cookie,可以使用如下命令:
Response.Cookies(“item-name”)(“sub-item-name”) = “sub-item-value”
设置cookie应用的域及路径及其有效期,我们使用:
Response.Cookies(“item-name”).domain = “domain-url”
Response.Cookies(“item-name”).path = “virtual-path”
Response.Cookies(“item-name”).expires = #date#
通常,客户只在对创建cookie的目录中的页面提出请求时,才将cookie随请示发住服务器。通过指定path属性,可以指定站点中何处这个cookie是合法的,并且这个cookie将随请求发送。如果cookie随对整个站点的页面请求发送,设置path为“/”。
假如Expires属性没有设置,关闭当前的浏览器实例时,cookie将被自动消除。
注意,我们在向浏览器发送任何输出时,已经创建了cookie。因为,这些cookie是页面HTTP报头的一部分。
在ASP 3.0中,缓冲的缺省状态是打开的,且没有输出被发送,除非使用Response.Flush指定做这个工作或者页面已到末端。这意味着创建cookie的代码可以在页面上的任何位置,直到任何输出“刷新”(flush)到客户端前,它都可以被执行。
要读现有的cookie,使用Request.Cookies集合。可以单独访问其中的项目,方法类似于创建它们时使用的方法。
StrSingleValue = Request.Cookies(“item-name”)
StrSubItemValue = Request.Cookies(“item-name”)(“sub-item-name”)
注意Request.Cookies集合(和所有其他Request集合一样)是只读的。Response.Cookies集合是只写的,事实上可以访问这个集合中一系列cookie的名称,而不是它们的值。
遍历Cookies集合
为了使用Cookies集合更加方便,可使用名称为Haskeys的附加属性。假如访问的cookie本身也是个集合,即它是一个多值的cookie,这将返回True。使用Haskeys属性,可以遍历完整的Request.Cookies集合,从而获得所有cookie的列表及它们的值。
For Each objItem In Request.Cookies
If Request.Cookies(objItem).HasKey Then
‘Use another For Each to iterate all subkeys
For Each objItemKey in Request.Cookies(objItem)
Response.Write objItem & “(“ & objItemKey & “) = “_
& Request.Cookies(objItem)(objItemKey) & “
”
Next
Else
‘Print out the cookie string as normal
Response.Write objItem & “ = ”& Request.Cookies(objItem) & “
”
End If
Next
这非常类似于前面的从Request.Form集合中提取多个值的复杂代码。但是这里可以使用Haskeys属性来判别每个条目是否为一个集合。而在Form例子里,必须查询Request.Form(item_name).Count属性,这是因为Form集合(和所有的除cookie外的其他集合)成员不可能是真正的集合。ASP只是做了“幕后”的工作,得到了每个多条目集合的值。
Form和QueryString的差异
了解了访问各种ASP集合的技术以后,需要解决另一个问题是:Form和QueryString集合之间的差异是什么?假如准备使用ASP,毫无疑问应该清楚这种差异,但需要参考HTTP工作方式来重新认识,理解它们。
通过HTTP从Web服务器请求页面或其他资源,有两个通用的方法。可使用GET方法直接获得资源,也可使用POST把值传给相应资源。GET方法是缺省的,可以看一下本章前面的一个HTTP请求的实例:
7/8/99 10:27:16 Sent GET /Store/Download.asp HTTP/1.1
假如把一个或多个成对的名称/值附在请求页面的URL后,就变成请求的查询字符串,且在QueryString集合中提供给ASP页面。单击Web页面、Email消息或其它文档的超链接,或在浏览器的地址栏中输入地址并按回车,或单击浏览器中的Links或Favorites按钮,所有这些都要使用GET方法。
因此,对这些动作中传递值给ASP的唯一方法是通过QueryString集合,把值附在URL后。
出现在Request.QueryString集合中并被访问的值,与前面看到的Form集合实例中的工作方式相同。URL和查询字符串的结合:
http://mysite.com/process_page.asp?FirstName=Priscilla&LastName=Descartes
可以采用如下方式访问在QueryString集合中提供的值:
strFirstName = Request.QueryString(“FirstName”) ‘Return “Priscilla”
strLastName = Request.QueryString(“LastName”) ‘Return “Descartes”
strRaw = Request.QueryString
‘Return “FirstName=Priscilla&LastName=Descartes”
窗体的GET和POST方法
在一个页面内使用<FORM>段时,可以设置打开的FORM标记的METHOD属性值为“GET”或“POST”,缺省值为“GET”。假如使用“GET”或省略其属性,浏览器将该值绑定在页面所有控件上,成为一个查询字符串,且附在被请求页面的URL上。
当这个请求到达Web服务器时,其值由ASP的Request.QueryString集合提供。然而,假如设置METHOD属性为“POST”,浏览器将值包装进发送服务器的HTTP报头中,通过Request.Form集合提供给ASP。
通过来说,可以在所有的HTML窗体中使用POST方法。然而,浏览器或服务器的URL字符串长度存在一定的限制。因此,附有长的字符串可能会引起溢出和某些字符串的字符被截掉。同时,查询字符串出现在浏览器的地址栏和所有的保存的链接和收藏夹中。不仅如此,还显露了通过Web服务器时在HTTP请求中不想显示的值,它也可能出现你的服务器和其他路由服务器的日志文件中。在HTTP请求报头中的值很少是可见的,并且不出现在日志文件中。
使用POST方法需要注意的小问题是,当用户重新下载<FORM>时,窗体的值将不再保留,其值为空且必须重新输入。然而,当附在URL上时,其值被存储为一个链接,将被保留,因此将出现在所有的URL与字符串结合的请求中,这或许是个优点也可能是个缺点,这根据应用而定(一些浏览器在客户端上能够在一定范围内自动保留一个页面上的值)。
另一点是URL与查询字符串的结合体不能包含任何空格或其他非法字符,否则的话,Navigator和一些其他的浏览器将出现问题。非法字符是那些用来分隔URL和查询字符串的部分,例如“/”、“:”、“?”和“&”(IE能够自动将空格转换为正确的格式——加号“+”,但其他的非法字符不能处理)。ASP服务器对象提供URLEncode方法处理这种变换,以后章节讨论相关内容。
查看Request和Response对象内容
到目前,主要讨论了一些理论问题,没有列举特别的实例。因为已经讨论过的内容多数情况下互相之间是密切相关的。然而本书为这一章提供了一系列的实例页面,说明Request和Response对象的大多数属性。应用所讲过的实例,能够理解这些页面,并可进行相应的修改,用它们作为试验实例。
本章及其他所有章节的代码样例均提供给用户,可以从Wrox出版社站点下载。
http://webdev.wrox.co.uk/books/2610
http://www.wrox.com/Store/Details.asp?Code=2610
必须首先在Web服务器的WWWRoot内的子目录下安装实例,然后使用浏览器访问Chapter02子目录,使用:
http://your_server_name_or_IP/subdirectory_name/Chapter02/Default.asp
这里your_server_name_or_IP/subdirectory_name是安装下载文件的本地路径。
1、查看Request对象成员
这提供一个包含选页的菜单用来试验Request和Response对象,首先选择Using the Request Object,如下图所示:
下图显示一个HTML窗体的实例,包含一些预先设置好的值,可以按自己的想法编辑这些值,然后点击“Submit”按钮。
这将打开一个页面,如下图所示,显示集合和TotalBytes属性的全部内容。第一屏显示的是Form、QueryString和Cookies集合。
注意,假如在窗体页中编辑了HTML控件的值,对于Cookies集合以及其他的集合,在读者的计算机上的页面上可能显示不同的值。
可以从“Form Collection”段中看到窗体上的HTML控件的值如何在ASP的Request.Form集合中表示。也可以用原始的<FORM>页(名称为request_form.asp)来试验和检测,以了解创建窗体的HTML和如何与相应值相联系。
这个页面后面是ClientCertificate集合。这里是空的,因为服务器不要求客户端提供证书。下面是的ServerVariables集合,下图的屏幕图显示的是集合中包含的有用的值。
在本书的后面附录中可以找到所有ServerVariables集合成员的一个列表,及其值的说明。然而,可从前面讨论的在请求页面时从客户端发出的HTTP报头中见到这些成员。当请求收到后,Web服务器也增加它本身的一些值到集合中,正如上面可以看到的运行在IIS 5.0创建的页面那样。
1) 页面是如何工作的
为了创建这个页面,使用了本章前面在对Form集合和如何访问其值的讨论中所看到的完全相同的代码。例如,遍历所有的集合(除Request.Cookies外),使用:
For Each objItem In Request.collection_name
Response.Write objItem & “ = “ & Request.collection_name(objItem) & “
”
Next
遍历Cookies集合,可以使用:
For Each objItem In Request.Cookies
If Request.Cookies(objItem).HasKeys Then
‘Use another For ... Each to iterate all keys of dictionary
For Each objItemKey in Request.Cookies(objItem)
Resonse.Write objItem objItem & “(“ & objItemKey & “) = “_
& Request.Cookies(objItem)(objItemKey) & “
”
Next
Else
‘Print out the cookie string as normal
Response.Write objItem & “ = “ & Request.Cookies(objItem) & “
”
End If
Next
为获得TotalBytes属性,可简单地使用:
Request.TotalBytes = <% = Request.TotalBytes %><P>
读者应该注意到,在两个集合中出现的某些值不是从窗体的HTML控件中直接得到的。QueryString集合包括了两个名为chapter和sample的值,如下图所示:
为在请求中创建这两个值,将一个字符串附在窗体的ACTION属性的URL上,这是可以接受的。工作方式与附在一个<A>元素的HREF属性上相类似。查询字符的值出现在QueryString集合中,且被POST的窗体控件值出现在Form集合中。
<FORM ACTION=”show_request.asp?chapter=2&sample=The+Request+Object” METHOD=”POST”>
为防止非IE类的浏览器出现错误,必须将查询字符串中的空格用加号“+”来代替,读者将在第4章的Server对象的URLEncode方法中看到更多这种情况。
2) 创建客户端的cookie
为了确保至少有些值出现在Request.Cookies集合中,增加一些客户端脚本代码到原始的<FORM>页面request_form.asp。将创建名称为VisitCount的多值cookie。另一个cookie是由另一个页面创建的,且已经存在于浏览器中。如下图所示,读者可以看到另外的cookie。
这是一段窗体被装载时设置文档对象的cookies属性的客户端代码:
<SCRIPT LANGUAGE=”JavaScript”>
<!--
documet.cookie = 'VisitCount=VISITS=3&LASTDATE=6%2F4%2F99+10%3A10%3A13+AM';
//-->
</SCRIPT>
另外,必须将内容进行编码,以便它能被正确地传送到服务器(同样的规则也适用于将查询字符串附到URL上)。在第4章中,讨论Server对象的URLEncode方法时,读者将了解到更多细节。
2、查看Response对象的成员
回到Chapter02实例的最初的Default.asp页面,这次选择“Using the Response Object”链接,这个页面显示的是Response对象的集合和属性的内容,且提供到所有Response对象方法的链接。
下图是使用浏览器Netsape Communicator 4.61的屏幕,用来证明使用的是纯服务器端和跨平台兼容技术。需要注意的是Cookies集合是为Response对象而建立的,仅显示cookie的名称而不显示其值。浏览该页时,可能得不到cookie或得到与这个页面不同的cookie。
各种Response属性说明了将要用来创建HTTP报头的一些信息。HTTP报头页面的其他部分(HTML和文本内容)被发往到客户端。这些属性中的一些以及所有的Response对象的方法均有链接,允许读者打开另一个页面来显示其使用情况。我们稍后再回到这些页面。
页面中的属性是通过读取相应的属性并插入到页面中创建的。由于这些是动态链接,通过<A>元素来选择。
<A HREF = ”headers/expiretet_form.asp”>Response.CacheControl</A>
= <% = Resposne.CacheControl %>
链接到每个方法是通过<A>链接元素,页面中唯一复杂的部分是Response.Cookies集合。通过只能访问cookie,读取Request.Cookies集合中的值。当访问Response.Cookie集合时,必须在发送任何输出到客户端之前结束对它的所有引用。因此在页面的上部,通过遍历集合创建页面的HTML放在一个局部字符串变量中。
StrCookies = “”
‘We can only read the key names and not the values because
‘the Response.Cookies collection is ‘write only'
For Each objItem In Response.Cookies
If Response.Cookies(objItem).HasKeys Then
‘Use another For Each to iterate all subkeys
For Each objItemKey in Response.Cookies(objItem)
StrCookies = strCookies & objItem & “(“ &objItemKey & “)
”
Next
Else
‘print out the cookie as normal
strCookies = strCookies & objItem & “
”
End If
Next
然后在页面的适当点上插入结果。
<P><DIV CLASS=”subhead”>The Response.Cookies Collection</DIV>
<I><A HREF=”cookies/setcookies.asp”>Response.Cookies</A>
is a write-only collection so the values cannot be displayed</I>
<% = strCookies %>
ASP中的cookie的使用
在前面所看到页面中,一些集合、属性和方法已经链接到其他的页面,用来显示Request和Response对象的各个特性细节,我们将在本章的其余的部分研究这些内容,我们将学习那些提供给ASP代码使用的集合、方法和属性的各种技术。
在本章前面已经看到了如何使用Request.Cookies和Response.Cookies集合来创建和阅读cookie,点击上面两个页面中的任一个的“Cookies”链接时,这个页面包含一些设置了三个cookie的值的ASP代码,且在页面上显示被执行的代码,如下图所示:
点击“Show Cookies”的链接时,cookie的内容就显示出来了。这是通过遍历Request.Cookies集合而得到的,这与在上一页所用的方式完全相同,如下图所示:
这个屏幕图显示的是运行前面看到的设置cookie值的代码的结果。可能会看到其他已经存贮在计算机系统里的cookie。然而,假如现在关闭浏览器然后重新打开浏览器,然后运行显示cookie的页面,除了TimedCookie外,所有的cookie都不见了,这是由于只有这个TimedCookie具有有效期的设置,其他的在浏览器关闭时,自动消失了。
1) cookie中存储用户的细节情况
可以使用cookie来存储这两类值:当浏览器关闭时我们不想保存的值(例如用户的注册信息)以及在用户访问站点时要保留的值。在每种情况下cookie的值对于来自用户浏览器的每个页面请求的ASP都是可用的。
然而,需要记住的是,cookie只有在对Cookie中的虚拟路径(path)内的页面发出请求时,才会发往服务器。缺省时,假如path的值在cookie中没有设置,则其值为创建cookie的页面的虚拟路径。为使一个cookie发往一个站点的所有页面,需要使用path=“/”。
这里是个实例,从自定义的Login页面中,将用户的注册信息存贮在一个cookie中,由于没有应用有效期,cookie值仅在关闭这个浏览器这前保留:
...
Request.Cookies(“User”)(“UID”) = “<% = Request(“UserName”) %>”
Request.Cookies(“User”)(“PWD”) = “<% = Request(“Password”) %>”
Request.Cookies(“User”).Path = “/adminstuff” ‘Only applies to admin pages
...
现在,在用户从adminstuff目录或其子目录请求的每个页面中,都可以找到这个cookie。假如它不存在,可以将用户重定向到注册页面:
If (Request.Cookies(“User”)(“UID”) <> “alexhomer”) _
Or (Request.Cookies(“User”)(“PWD”) <> “secret”) Then
Response.Redirect “login.asp?UserName=” & Request.Cookies(“User”)(“UID”)
End If
...
由于把cookie中的用户名放在Response.Redirect的URL查询字符串中,假如在口令输入时出现错误且希望用户不必重新键入用户名,可以在login.asp页面中使用它:
<FORM ACTION=”check_user.asp” METHOD=”POST”>
<INPUT TYPE=”TEXT” NAME=”UserName”
VALUE=”<% = Request.QueryString(“UserName”) %>”><P>
<INPUT TYPE=”SUBMIT” VALUE=”LOGIN”>
</FORM>
2) 修改现有的cookie
可以使用ASP修改现有的cookie,但不能只修改cookie中的一个值。当更新一个在Response.Cookies集合中的Cookie时,现有的值将丢失。我们可以用如下代码创建一个cookie,可以使用:
Response.Cookies(“VisitCount”)(“StartDate”) = dtmStart
Response.Cookies(“VisitCount”)(“LastDate”) = Now
Response.Cookies(“VisitCount”)(“Visits”) = CStr(intVisits)
Response.Cookies(“VisitCount”).Path = “/” ‘Apply to entire site
Response.Cookies(“VisitCount”).Expires = DateAdd(“m”,3,Now)
假如想要更新Visits和LastDate的值,必须先不需改变的所有值,然后重写整个的cookie:
datDtart = Response.Cookies(“VisitCount”)(“StartDate”)
intVisits = Response.Cookies(“VisitCount”)(“Visits”)
Response.Cookies(“VisitCount”)(“StartDate”) = dtmStart
Response.Cookies(“VisitCount”)(“LastDate”) = Now
Response.Cookies(“VisitCount”)(“Visits”) = Cstr(intVisits)
Response.Cookies(“VisitCount”).Path = “/”
Response.Cookies(“VisitCount”).Expires = DateADD(“m”,3,Now + 1)且对于几乎所有的其他Response方法和属性,应该在写入任何内容(即打开<HTML>标记或任何文本或其他的HTML)到响应之前完成这个工作。