使用servervariables集合
当讨论request对象内容时,要研究的集合之一就是servervariables集合。这个集合包含了两种值的结合体,一种是随同页面请求从客户端发送到服务器的http报头中的值,另外一种是由服务器在接收到请求时本身所提供的值。为显示servervariables集合中值的使用方式,在request object页面(show_request.asp)中,点击“servervariables examples”链接,打开另外一个页面,如下图所示:
下图所示窗口显示的是servervariables集合中一些非常有用的值的一个子集。
“自引用”页面
在servervariables集合中返回的值包含web服务器的详细信息和当前页面的路径信息。在任何地方创建一个页面都可使用这些信息。例如创建一个“自引用”页面,此页面能够再次调用自身完成另一项任务,我们可以用以下代码:
” method=”post”>
同样的效果可以用http的“script_name”值获得:
” method=”post”>
使用元素打开一个不同页,可以使用:
...
...
”>next page
...
即使原始页面的名称或位置发生变化,这些实例都能正常工作,因为使用了当前页面的路径信息(当然,第二个例子在分离的目标页的名称发生变化时运行会失败)。
换句话说,如果为搜索引擎的子会话自动建立url,可以收集servervariable的一些值:
strfullurl = http:// ;& request.servervariables(“local_addr”) _
& “:” & request.servervariables(“server_port”) _
& request.servervariables(“path_info”)
这将创建一个完整的url包括端口号(这种情况下,不是标准值80)。例如,结果可能是:
http://194.74.60.254:1768/thispath/thispage.asp
检测浏览器的版本
servervariables集合中,另外一个有用的值是用户浏览器的用户代理字符串。在“detecting the browser type”页面(browsertype.asp),使用servervariables集合中的“http_user_agent”值来获得用户代理字符串,一些脚本用来解析该信息并寻找生产厂家名称和浏览器版本。
对ie 5.0和navigator 4.61的搜索结果分别不同,对于其他厂家的浏览器,可以得到一个链接在alta vista web站点自动开始搜索厂家的名称。
注意,netscape在用户代理字符串中不提供厂家的名称,因而无法绝对保证一个浏览器一定是navigator。
检测浏览器的语言
servervariables集合中另外一个有用的值是“http_accept_language”,它包含了一个当浏览器安装时指定的,或硬编码进用户的地区版本的语言代码。语言代码的例子有en-us(英国、美国)、de-at(德国、澳大利亚)和es-pe(西班牙、秘鲁)。
语言代码可以是一般的且省略方言标识:例如,在我们的站点wrox者,大批浏览者都是将en(英语)作为语言代码。
因此,可以检测语言代码并自动装载一个合适的特定地区或指定语言版本的页面。
strlocale = lcase(left(request.servervariables(“http_accept_language”),2))
select case strlocale
case “en”: response.redirect http://uk_site.co.uk/”
case “de”: response.redirect http://de_site.co.de/”
case “fr”: response.redirect http://fr_site.co.fr/”
‘... etc
case else: response.redirect http://us_sitel.com/”
end select
或者根据特定的方言,重定向页面:
strlocale = lcase(request.servervariables(“http_accept_language”))
select case strlocale
case “en-gb”: response.redirect http://uk_site.co.uk/”
case “en-us”: response.redirect http://us_site.com/”
case “es-pe”: response.redirect http://es_site2.co.pe/”
‘...
case else: response.redirect http://us_site1.com/”
end select
其他有用的servervariables集合的值
可以访问和使用servervariables集合中的任何一成员,控制asp页面响应一个请求的方式。可以检查一个浏览者访问站点时使用的是否是缺省端口80或还是另一个。在这个例子里,寻找通过端口443的访问——这个端口提供的是安全套接字层(secure socket layer,ssi)访问(和其他的协议),且将它们重定向到一个相应的页面。
if request.servervariables(“server_port”) = “443”) then
response.redirect “/securesite/default.asp” ‘secure user
else
response.redirect “/normalsite/default.asp” ‘non-secure user
end if
假如要求浏览者注册且由服务器验证(而不是允许他们在web服务器的iuser帐号下匿名访问,这个问题将在后面章节中详细讨论),可以查询用户名称,来判定正在与我们打交道的用户是谁,是否装载页面给该用户。例如,下面的这个代码将只向名为administrator的用户显示管理链接。
...
change display configuration
change display colors
change keyboard configuration
administer all users
administer logon information
...
注意asp不填写servervariables集合直到你访问其中的一个成员。首次访问该集合的一个成员将使iis得到它的全部,应只在需要时才使用servervariables集合。
其他request和response技巧
现在,来看一下几个使用request和response对象的有用技巧,包括:
· 连接、缓冲和页面重定向的管理。
· http报头、缓存与“到期”页面的操作。
· 利用客户证书。
· 创建定制的日志文件消息。
1. 连接、缓冲和页面重定向的管理
asp的一个很有用的特点就是使用户能够从一个asp网页转向到另一个网页(asp或html),或另一个源文件(例如一个zip文件或文本文件)。这对用户来说是透明的,实际上是浏览器做这个工作。当使用response.redirect方法来载入一个新的网页时,实际上是发送回一个特殊的http报头到客户。此报头为:
http/1.1 302 object moved
location /newpath/newpage.asp
浏览器读到此报头信息,并按location值的指示载入页面。这在功能上与在web页中使用客户端html标记相同,例如:
这带来的一个问题是,服务器与用户之间的代理服务器可能会提供它自己的包含与新页面的链接的消息,而不是直接载入新页面。而且浏览器根据厂商和版本可能做同样的工作。这就去除了假定的透明,而且对用户来说一直收到的是错误信息,则对你的站点的访问变得比较麻烦。
在发送诸如文本或html等任何页面内容后,我们就不能再使用redirect方法。然而,一个看起来能够限制“代理服务器影响”的方法是,先确定没有输出(包括http报头)被发送到客户。在asp 2.0中,必须打开缓冲,然后使用clear方法来清空缓冲区:
response.buffer = true
‘some condition to select the appropriate page:
if request.servervariables(“server_port”) = 1856 then
strnewpage = “/newpath/this_page.asp”
else
strnewpage = “/newpath/the_other_page.asp”
end if
response.clear
response.redirect strnewpage
在asp 3.0中,缓冲缺省为打开,所以第一行可被忽略,但它是无害的,而且能确保我们的网页即使在asp 2.0环境中也仍然能工作。
与其使用这种类型的http报头重定向,不如使用asp 3.0的一个新特性,它允许我们通过server对象的transfer方法转换为执行另一个网页,我们将在第4章进一步研究这个问题。
1) asp页面缓冲区
正如已看到过的,iis 5.0中asp 3.0页面缓冲是缺省打开的,在早期的版本中是缺省关闭的。微软告诉我们缓冲在iis 5.0中提供了更有效的网页传送,这就是缓冲缺省状态被改变的原因。在大部分情况下,这对我们没有影响。但是,假如有一个非常大的网页,或一个用asp或别的服务器端代码和组件花费一定时间创建的网页,当其各部分完成时,我们能够分批刷新它们到客户:
...
... code to create first part of the page
...
response.flush
...
... code to create next part of page
...
response.flush
...
有时可能希望在页面结束之前的某些点上停止代码的执行,可以通过调用end方法去刷新所有的当前内容到客户并中止任何进一步的处理过程。
...
... code to create first part of the page
if strusername = “” then response.clear
...
... code to create a new version of this part of the page
...
这里有两上演示缓冲和重定向的实例网页,可以从“response object”主页面(sow_response.asp)下载它们。第一个response.redirect例子网页命名为redirect.asp,它在缓冲的页面中定入一些内容,清除缓冲区,并重定向到另一个网页:
for intloop = 1 to 1000000
response.write “.”
next
response.clear
response.redirect “show_redirect.asp”
response.end
目标页show_response.asp,做同样的工作,但重定向则是回到“response object”主页。因为这些网页都在缓冲区内,而且所有的输出在重定向之前必须清除,故在浏览器中没有可见的输出。然而,可以通过观察浏览器的状态看到发生的每一次重定向。如下图所示:
在“response object”主页中,点击“response.flush”链接将打开第二个示例网页usebuffer.asp,它简单地遍历一个字符串的每一个字符,以一定的延迟将它们刷新到客户,这虽是web服务器和asp极低效率的使用方式,但它演示了缓冲的工作方式。
下面是所要求的最小化的asp代码,注意我们分别把每个字符刷新到浏览器,因为不这样的话它将被存放在缓冲区中,直至网页完成:
strtext = “this text has been flushed to the browser using “ & _
“response.flush
”
for intchar =1 to len(strtext)
for intwrite = 1 to 100000
next
response.write mid(strtext,intchar,1)
response.flush
next
2) response.isclientconnected属性
isclientconnected属性在asp 2.0中已经存在了,但却有些不可靠。在其返回一个准确的结果之前必须发送一些输出到客户。这一问题在asp 3.0中已被解决。现在这一属性可被自由使用。
isclientconnected是观察用户是否仍连到服务器和正在载入asp创建的网页的有用方式。如果用户断开连接或停止下载,我们就不用再浪费服务器的资源创建网页,因为缓冲区内容将被iis丢弃。所以,对那些需要大量时间计算或资源使用较多的网页来说,值得在每一阶段都检查浏览器是否已离线:
...
... code to create first part of the page
...
if response.isclientconnected then
response.flush
else
response.end
end if
...
... code to create next part of page...
1. 操作http报头
我们已经在几处见到asp如何创建或修改在响应页面请示时被发送到客户的http报头。在response对象中有几个属性和方法可帮助我们做到一点。下面是一些报头方法:
· 控制缓存和有效期。
· 创建状态和定制的http报头。
· 指定mime类型或内容类型。
· 添加pics标签。
接下来将简要地研究每一个方面。可在“response object”主页(show_response.asp)上,单击相关属性名或方法名,来检查我们所说的属性和方法,如下图所示:
1. 缓存和“到期”asp网页
用户的浏览器以及他们和服务器这间的任一代理服务器,都可以缓存html和用asp创建的网页。当用户随后请求页面时,浏览器就发送一个“最新修改”的请求到服务器(使用一个包含缓存版本的日期的http_if_modified_since报头),询问网页是否已被修改。
若没有被修改,服务器应用状态码和消息“304 not modified”来响应,浏览器将使用缓存的内容而不会通过网络下载一个副本。若已经存在已修改的版本,它就会与“200 ok”状态码和消息一道被发送出去。
1) response.cachecontol属性
其他的一些因素也会影响这一处理过程。然而,任一被网页使用的网络路由内的代理服务器(一般位于客户机端),能被通过设置response.cachecontrol属性为private来放弃缓存网页。在asp 3.0中对asp网页这是缺省的,不用设置。但在网页为个别访问者特别定制时尤其有用。这可以阻止别的在同一网络上的用户进入同一网页。当cachecontrol的属性值被设定为public时,允许服务器缓存网页。注意,一些代理服务器可能表现得不尽相同,或忽视或越过这个报头。
在ie4中,在代理服务器缓存可用时,有可能得到一个虚假的“this page has expired”消息。我们已提供了一个网页(expiretest_form.asp),可以通过自己的代理服务器在网络上做试验,来检查这一属性的影响。可以通过在“response object”主页中单击“response. cachecontrol”链接来显示这个网页。如下图所示:
这一页面提交到expiretest_result.asp网页时,能够设置response.cachecontrol属性,然后在网页中插入值和脚本被执行的时间:
<%
if request.form(“public”) = “on” then ‘cache-control check box was ticked
response.cachecontrol = “public”
else
response.cachecontrol = “private”
end if
%>
<html>
...
cache-control is: <b><% = response.cachecontrol %></b><p>
value in text box is: <b><% response.write request.form(“textbox”) %>
<%
response.write right(“0” & hour(now),2) & “:” & right(“0” & minute(now),_
& 2) & “:” & right(“0” & second(now),2)
%></b>
通过单击浏览器上的“back”和“forward”,能看到代码是自动执行还是使用缓存的副本,如下图所示。结果随浏览器的不同而变化。
2) response.expires和response.expiresabsolute属性
控制缓存的网页存放时间的两个属性为response对象的expires和expriesabsolute属性。response.expires定义了风页在从缓存区被丢弃前应保持有效的时间长度,以创建以来的分钟数形式表示。expiresabsolute属性为到期时间设置了一个绝对的日期和时间。
我们提供一个命名为addheaders_form.asp的例子网页,用于演示如何使用这些属性。在“response object”主页中单击对这两种属性的链接,如下图所示:
在这一页面中,可加入自己定制的http报头,并可设置一些影响响应的http报头的多种属性。在“提交查询内容”按钮上单击时,页面show_headers.asp在返回的数据流中添加所选的报头,然后显示用来完成此操作的代码,显示相应的执行时间,可用来检查页面是被缓存还是被再次执行,如下图所示:
show_headers.asp网页中的代码创建和添加http报头,程序如下:
<%
‘write http headers before any other output
if request.form(“expires”) = “on” then _
response.expires = request.form(“expires_value”)
if request.form(“expiresabs”) = “on” then _
response.expiresabsolute = request.form(“expiresabs_value”)
if request.form(“lastmod”) = “on” then _
response.addheader “last-modified”, cstr(request.form(“lastmod_value”))
if request.form(“pragma”) = “on” then _
response.addheader “pragma”, cstr(request.form(“pragma_value”))
if request.form(“refresh”) = “on” then _
response.addheader “refresh”, cstr(request.form(“refresh_value”))
if request.form(“addheader”) = “on” and len(request.form(“addheader_name”)) then _
response.addheader cstr(request.form(“addheader_name”)), _
cstr(request.form(“addheader_value”))
if request.form(“status”) = “on” then _
response.status = request.form(“status_value”)
%>
<html>
...
... show code and execution time
...
其余部分仅仅是显示已被执行的代码和执行时间。读者会注意到包含在网页中的定制的报头“pragma”(至今我们还没讨论过)。一些(先前的)代理服务器使用它作为网磁是否应被缓存的指示。缺省是网页被缓冲,除非接受到http报头“pragma=no-cache“。
2. 创建状态码和定制的http报头
可使用先前在实例网页中所看到的response对象的addheader方法来创建自己的状态码或自己喜欢的定制的报头。这一方法需要两个参数:http报头名称或一个包含其值或分配给它的值的字符串。作为一个例子,下面的代码在页面中添加refresh报头:
response.addheader “refresh”, ”60;url=newpath/newpage.asp”
这等同于客户机端<meta>元素:
<meta http-equiv=”refresh”, “60;url=newpath/newpage.asp”
换句话说,也可配合status属性使用addheader方法使浏览器载入一个新的页面:
response.status = “302 object moved”
response.addheader “location”, “newpath/newpage.asp”
这等同于使用response.redirect方法:
response.redirect “newpath/newpage.asp”
response.status属性可被用来发送一些所需要的状态消息,例如添加如下几行:
response.status= “401 unauthorized”
response.addheader “www-authenticate”, “basic”
强制浏览器显示一个用户名/口令对话框,然后使用basic验证把它们发送回服务器(将在本书后续部分看到验证方法)。
3. mime类型和内容类型
当我们想向浏览器发送一个动态创建的字符串,而且它们自己提供给浏览器时没有直接指明内容类型,而是提供表示是否是磁盘文件的扩展名时,response.contenttype是非常有用的。除非特别指定,所有asp创建的网页缺省都为“text/type”。内容类型的标识符是mime类型(mime代表multi-purpose internet multimedia extension或multi-pupose internet mail extension,通常依据上下文来定)。
例如,若发送到客户的数据注解是通过从数据库读二进制值创建的图片,就需要在发送任何内容之前添加合适的content-type报头:
response.contenttype = “image/jpeg”
假如从一个数据库创建一个xml文件,使用miem类型“text/xml”;并且如果正在创建一个文本文件可以在文件编辑器中显示或作为一个磁盘文件在客户上被存储起来,使用“text/text”。
4. 添加pics卷标
respnse.pics属性仅仅是添加一个pics(platform for internet content system)卷标到页面上,方式与通常用<meta>标记所用的方式相同:
quot = chr(34)
strpicslabel = “(pics-1.0” & quot & http://www.rsac.org/ratingsv01.html”_
& quot & “ 1 gen true comment “ & quot _
& “rsaci north america server” & quot & “ for “ & quot _
& http://yoursite.com” & quot & “ on “ & quot _
& “1999.08.01t03:04-0500” & quot & “ r (n 0 s 0 v 2 l 3))”
response.pics(strpicslabel)
这段代码添加了如下的pics卷标:
(pics-1.0 http://www.rsac.org/ratingsv01.html” 1 gen true comment “rsaci
north america server” for http://yoursite.com” on “1999.08.01t03:04-0500”
r (n 0 s 0 v 2 l 3))
要得到关于pics的更多的信息,或了解更多的定义页面内容的方式,请检http://www.rsac.org/站点。
在internet service manager中定义报头
在第1章,已经说明了如何在internet service manage(mmc插件)应用程序中设置每个web网站和iis 5.0目录的属性,这就定义了使用此站点或目录资源发送到客户机的所有请求的http报头,也就提供了使用每个网页中的asp脚本代码设置这些属性的替代方法。
在web站点或目录上右击鼠标并选择“properties”,在其对话框的“http headers”选项卡中,可设置页面内容有效期的相对时间或绝对日期,定义定制的报头,创建pics内容等级标签,也可以通过mime类型映射来定义内容类型,如下图所示:
在上图中,可以看到已创建了自定义的refresh http报头,应用于从此目录载入的所有网页。即每一分钟自动地重载(刷新)一次(对于显示棒球比赛的最近比分是非常理想的,但对服务器而言负担太重了)。custom http headers栏的edit对话框如下图所示:
要在“mime map”框中添加自定义的内容类型映射,只需在“properties”主对话框中单击“file types”按扭把它们添加到清单中即可,如下图所示:
当使用http报头开始试验时,你很快会发现不是所有的浏览器表现都相同,许多浏览器以不同的方式响应不同的http报头,使得可靠地建立一个普遍适用的原则有时极为困难。
2. 使用客户证书
假如设立了一个安全的web网站或部分内容具有安全机制的网站,可安装一个数字服务器证书,通过允许访问者使用证书中的加密的细节,来验证服务器。每一次对该站点或目录的页面请求,服务器都将发送证书的一个副本,浏览器可检查这个副本以确定正在和谁交谈。
同样,也可设置服务器,要求用户在进入网站时提供一个有效的数字证书。他们可从很多来源获得此证书,例如verisignhttp://www.verisign.com)或thawte consultinghttp://www.thawte.com)。读者将在第25章看到这一处理过程的细节。
这些情况都使用了request对象的clientcertificate集合的值,本章的实例代码中,已包含了一个显示用户如何使用些集合值的一些方法的页面。
这一网页被命名为showcert.asp,而且其所做的一切就是遍历clientcertificate集合显示其包含的所有值。可使用以前经常使用的简单代码来完成它,唯一的不同之处就是建立一个html表以容纳结果,并将其截为每60个字符一组。
<tabel cellpadding=0 cellspacing=0>
<%
for each keyitem in request.clientcertificate()
stritemvalue = request.clientcertificate(keyitem)
if len(stritemvalue) > 90 then stritemvalue = left(stritemvalue, 60) & “..etc.”
response.write “<tr><td>” & keyitem & “ = “ & stritemvalue & “</td></tr>”
next
%>
</table>
运行结果如下图所示:(由于豆豆没有申请服务器证书,该图略)
使用客户证书重定向
一旦要求所有访问网站或部分网站的浏览者给出的其客户证书,就可以使用其包含的信息来制作我们为此用户创建的网页。例如,可使用他们的证书的organization条目来自动使他们重定向到该网站的指定部分,使别的访问者重定向到别的地方:
if request.clientcertificate(“subjecto”) = “wrox press inc” then
response.redirect “/wrox_staff/default.asp” ‘wrox staff site
else
response.redirect “/public/default.asp” ‘normal public site
end if
相应地,可使用country条目来使访问者重定向到一个相应的网站:
select case request.clientcertificate(“subjectc”)
case “uk”: response.redirect http://uk_site.co.uk/”
case “de”: response.redirect http://de_site.co.de/”
case “fr”: response.redirect http://fr_site.co.fr/”
‘... ect.
case else: response.redirect http://us_site.com/”
end select
3. 读写二进制数据
有两个方法提供了对从浏览器发送到服务器的http数据流和从服务器返回到浏览器的数据流的二进制数据访问。request.binaryread方法可得到指定要读取的字节数的参数,并返回变体类型的数组,其中包含从请求的post段中得到的字节(例如在asp的form集合中数据)。下面的程序读数据的头64个字节:
varcontent = request.binaryread(64)
假如使用了binaryread方法,以后就不能访问asp的request.form集合。同样,一旦我们采用任何方式引用了request.form集合,就不能使用binaryread方法。
把二进制数据写进asp创建的响应流中也是可能的,可采用binarywrite方法。需要给其提供想写到客户的字节的变体类型数组:
response.binarywrite(varcontent)
这些方法都很少使用,除非从一个数据库创建非html源才用到这些方法。使用的一个实例就是从数据库读取组成图像的字节,并使用binarywrite方法把它发送到客户。
4. 创建定制的日志消息
假如设置了服务器,以w3c extended log file format格式将请求记录到一个文本文件,可使用response.appendtolog方法在日志文件条目的结尾处添加一条消息字符串。若想为特定的网页存储一些值或消息,或在脚本中出现了特定的情况时,这种方式是非常有用的。
例如,通过的intranet的“stationary order”应用程序,可以记录超过特定的条目数目的雇员的部门号码:
...
if intitemcount > 25 then
response.appendtolog “large order from ‘” & strdept & department.”
end if
...
设置扩展的日志
要使用appendtolog方法,必须激活w3c extended log file format日志设置。该设置方法是,进入properties对话框中的web site选项卡,选中enable logging复选框,选择w3c extended log file format并单击properties按钮,如下图所示:
在出现的extended logging properties对话框中,可选择想包括进日志文件的条目。确保选中uri stem,否则appendtolog方法将失败,如下图所示:
我们提供了一个试图在日志文件中写入一个条目的简单实例页面,可从request object主页(show_request.asp)中的appendtolog方法链接处打开它。这一页面所做的全部工作就是创建一个包含当前日期和时间的简单字符串,然后执行appendtolog方法:
strtoappend = “page executed on ” & now
response.appendtolog strtoappend
结果如下图所示:
小结
本章已经开始了对asp 3.0的研究,而且我们也看到了asp 3.0如何与internet informateion server 5.0共同工作,以提供一个易用的、高效的创建动态web网页和web应用程序的方法。当然,仍有一些地方需要去研究,本章仅仅是学习了asp内置的两个最基本的对象。
这两个最基本的对象是request和response对象,允许我们访问和使用作为客户机/服务器会话一部分的值,无论用户何时从web网站请求和载入一个网页或资源,这种会话就会进行,意味着request对象能够提供对用户请求的全部内容的访问,同时response对象允许创建和修改服务器发回的响应。
这些对象能够通过集合和属性揭示会话的各个部分,并提供了多个能用来检索和修改各段的方法。假如把它们当作分解用户请求和使用相应的内容创建响应的工具,这有助你理解究竟发生了什么。这也将有助于理解各种方法如何影响客户、服务器和正在创建的网页。