分析如何使用微软提供的ASP.NET来对动态产生的URL地址进行网址重写。 网址重写是实现一种截取网址请求并将其进行处理后重新指向到一个指定的网址的过程。作者本人在对各种实现网址重写的技术进行研究和探讨后得出的经验和方法,希望能对您有所帮助。
稍微花点时间看一看你做的网站里头的URL地址,你看到类似这样的地址吗?也许你会出于某种目的把大量的页面文件从一个目录甚至一个网站转移到其他地方,而许多访问者出于个人兴趣或者研究目的之前就已经将原有网址收藏了起来, 如果这时他从收藏夹打开该页面的时候发现这已经是坏链了。本文旨在介绍如何使用网址重写将那些“难看”的网址转换成比较有实际意义的网址,使其便于记忆。例如将转换成如下地址:。我们甚至发现 网址重写技术可以解决令人头疼的404错误,或者说它可以创建一个智能化的404错决方案。
如上所述,网址重写是实现一种截取网址请求并将其进行处理后重新指向到一个指定的网址的过程。 在网址重写执行的期间,相应处理程序处理被请求的网址,从中提取出相关的值,然后重新指向一个新的指定地址。例如:由于一次网站目录调整,原有的 /people/ 子目录下的所有网页全部移动到/info/employees/目录,原访问者从收藏夹或者其他什么地方点击链接发出访问/people/目录下的文件的请求时,你肯定希望他还是能通过原有地址看到和原来相同的页面,但实际上看到的却是网址重写指向的新目录下的相应文件。
在老版本ASP中,使用网址重写技术的途径很少,要么写一个 ISAPI过滤器,要么购买第三方厂商提供的网址重写组件,然而在微软提供的ASP.NET下你可以通过多种方法很简单地开发出自己的网址重写软件,以满足自己各种不同的需要。本文将和你一起讨论这门针对ASP.NET开发人员的实现网址重写的技术,然后举一些网址重写实际应用的例子。在我们深入探讨网址重写技术的细节之前,我们先看一下日常使用网址重写技术实现的场景。
创建一个数据操作的ASP.NET程序最常见的就是一个aspx页面后面带上一些查询参数集合。例如在设计一个电子商务网站的时候,假定你设计了一项功能允许用户浏览待售的商品,为了更加方便操作,你设计了一个页面displayCategory.aspx将商品按照给定的分类显示,那么该分类下的商品显示页面上应该在页面文件对应网址后面加上了一个商品分类的查询参数,例如用户要查询待售的“装饰品”,在数据库中所有的装饰品数据对应的分类编号CategoryID的值为5,那么用户会访问如下网址:。
创建一个包含类似这样网址的网站最终有两种结果,首先从最终用户的角度来观察,这个网址有些杂乱, 可行性分析专家Jakob Neilson(主页: ) 选择网址显示方式时候考虑如下要求(参考网址:):
我想还应该在上述列表中再增加一条: 是否便于记忆。这个地址没有一个地方符合Neilson标准的任何一条,也不便于记忆。当然,对于有经验的网络开发专家来说,他们很熟悉这种键值对构成的查询参数结构体系,然而对于普通用户来说输入这些带有参数的网址实在是太麻烦了。
一种较好的方法就是使用一种比较直观且容易记忆的方式来将网址表示为: 乍一看很容易就会推断这个网址所对应的内容极有可能会是显示装饰品(Widgets)信息,这个网址就变得更加容易记忆和!然后我告诉我的同事:“请查看这个网址:”不用我说第二遍,她可能一次就把地址敲到浏览器上了(你也可以在亚马逊()的网站上这样尝试一下)。很快就浏览器上就列出了装饰品(Widgets)的内容。这里“隐蔽性”表示:用户可以自行变更网址的结尾,例如输入:就能看到全部分类相关的商品列表或者列出所有相关商品分类目录列表。
注:用上述简单的变更网址内容的方法来构思一下如今的比较流行的Blog网站生成的网址。例如:要查询2004年1月28日所发的帖子,只需输入 即可,如果将网址裁减为 则显示 2004年1月份的帖子 ,同样将月份裁减掉得到 则显示出2004年全年所发的帖子。
网址重写技术除了用于将复杂的网址简单化之外,它还能用于处理因网站目录调整或者其他原因导致产生大量的无效链接和过期。
在探讨如何实现网址重写这项技术之前,很有必要了解一下IIS是处理所接收的Web请求的机制。 当一个Web请求到达IIS Web服务器时,IIS会根据所请求的文件后缀名来决定如何处理该请求,IIS可以处理诸如HTML页面、图片、静态内容,或者将请求转发给ISAPI应用程序,由该ISAPI应用程序处理后生成HTML静态内容返回给IIS,最后由IIS将请求结果发送回给客户端。(一个ISAPI应用程序就是一套编译好能随时在后台运行的类库,它的任务就是根据请成相关的内容。)
例如:如果IIS接收到一个对Info.asp的请求,它会将该请求转交给 asp.dll来处理,该ISAPI应用程序调出并执行所请求的ASP页面,然后把生成的HTML代码返回给IIS,IIS最后把内容发送回请求客户端。对于ASP.NET页面,IIS则将请求转交给名为 aspnet_isapi.dll的ISAPI应用程序来处理,该ISAPI应用程序 调用托管的ASP.NET工作进程来处理该请求,并将生成的HTML代码返回给请求客户端。
你可以自定义IIS, 将某一类扩展名映射到指定的ISAPI应用程序,图一显示了IIS管理工具中的应用程序配置对话框。
关于对IIS如何管理所接收的请求的详细探讨有些超出本文内容,,重要的是要了解引擎只负责处理对扩展名已经被正确配置映射到aspnet_isapi.dll的网络请求。
除了将请求的文件扩展名映射到相应的ISAPI应用程序外,IIS还执行一些其他工作。例如 IIS还主动对发出请求的客户端用户进行授权,并判断已授权用户是否对其请求的文件拥有访问权限,在一个请求过程的全部生命期内,IIS的处理经历了几个阶段,在每一个阶段IIS都生成一个事件,而该事件可以被ISAPI过滤器实时操控的。
如同ISAPI应用程序一样, ISAPI过滤器也是一块块安装在Web服务器上的非托管代码。 ISAPI应用程序用于对所接收的特定文件类型做出响应,而ISAPI过滤器含有对IIS生成的事件做出响应的代码(contain Code),甚至可以编辑进出的数据。ISAPI也含有众多应用程序,包括:
本文所探讨的用ASP.NET实现的网址重写技术就是 基于ISAPI过滤器用于网址重写的技术内容,然而我们仍然要讨论一下究竟是使用ISAPI过滤器还是使用ASP.NET应用程序提供的技术来实现网址重写技术。
ASP.NET问世之前,在IIS Web服务器上的网址重写功能需要通过ISAPI过滤器来实现,自从这个家伙问世后我们就能通过ASP.NET来实现URL重写了,因为ASP.NET的解释引擎与IIS有极大的相似之处,产生这些相似性主要是因为 ASP.NET:
和IIS一样,在一个请求的整个生命期内,ASP.NET对该请求的处理状态发出的状态改变信号引发相应的事件。例如:
如上所述, 可以创建ISAPI过滤器并用于相应IIS引发的事件,同理,ASP.NET也提供了
,并允许它 针对请求处理期间引发的事件生成相应的事件委托。事实上ASP.NET引擎 处理每一个请求调用大量的事件委托。
中的一个,它 首先检查是否使用表单授权,如果是的话,它 将检查用户是否已授权,如果没有授权则自动把用户重定向到指定的登录页面。(即:在asp.net中可以直接记录并判别用户登录授权的问题了!)
回忆在IIS中,一项请求最后被转交给一个ISAPI应用程序处理,该应用程序针对每一项请求进行处理并返回相应的数据。例如,客户端发出一个访问经典ASP页面的请求,IIS将该请求转交给asp.dll程序处理,asp.dll针对该请求执行asp页面内容,并返回HTML编码。ASP.NET也使用了类似的手法,ASP.NET引擎在将这些
的实例。)最终的委托呈现并响应所请求的HTML编码,并发送回IIS,IIS则将HTML返回给请求客户端。
图二描绘了一个针对ASP.NET资源的请求所经过的处理流程。首先,IIS接收到该请求并将其转交给aspnet_isapi.dll。其次,ASP.NET引擎将一些
只需简单的写入nfig文件;如果是 由指定的Web应用程序调用则需在该程序的web.config配置文件中添加几行XML标记。
,只需向该Web应程序的web.config配置文件中configuration\System.Web节中添加下列几行:
则是 在nfig文件中configuration\System.Web节中添加<httpHandler>标记,例如:
回忆上文,对每一个接收到的请求相应的HttpHandler来处理并呈现相应内容,该决定于所接收请求的verb和path的内容,verb为HTTP请求的类型:GET或者POST,path则为请求的文件的径和文件名。如果我们打算用一个
来处理所有GET类型和POST类型的并且文件扩展名为.scott的内容,可以在nfig相应配置节中加入下列标记:
所使用的文件扩展名必须已经在IIS中做指向引擎的映射,在.scott扩展名的例子中,如果我们所使用的.scott扩展名如果没有在IIS中做指向ASP.NET引擎的映射的话,假定对foo.scott文件发出请求,该请求 将导致IIS将foo.scott文件内容直接呈现给客户端,为了能够让
处理该请求,必须将.scott扩展名在IIS中做指向ASP.NET引擎的映射,之后IIS才能正确地将.scott的请求转交给相应的
网址重写技术不但可以在IIS Web服务器一级通过ISAPI过滤器实现,而且还可以在ASP.NET一级通过
实现。本文主要关注在ASP.NET一级实现网址重写技术,所以此时不必关注在ISAPI应用程序中实现网址重写的技术细节,而且有很多第三方厂商提供的ISAPI过滤器。
类中包含有关于特定HTTP请求的HTTP规范信息。ASP.NET引擎每接收到一个特定请求后便针对该请求创建一个特定的实例,这个类包含一些属性诸如:
方法之外,.NET Framework 1.1版还提供了另外一些重载版本,其中一个重载版本接收三个输入字符串参数,这种交替的重载形式不仅仅只是设置
以前文所构建的那个站点为例,可以通过/info/employee.aspx?empID=EmployeeID来访问每一个雇员的信息。为了使这个网址更加地具有“隐蔽性”,我们可能会使用更加容易理解的访问方式如:/people/雇员名.aspx。这里就有了一个网址重写的案例:当接收到对/people/ScottMitchell.aspx的请求的时候,我们就得使用网址重写使得对该页面的请求被重写指向到先前使用的/info/employee?EmpID=1001地址。
的时候,必须决定如果该网址需要被重写的话,究竟应该在整个请求的生命周期期间的那一个点来使用。乍一看着有些,但是这个决定以重大而且微妙的方式影响到你的应用程序。之所以作出对网址重写点的选择是因为内嵌的ASP.NET
检查并确认请求者是否对所访问的网址拥有权限。该Url授权可以在nfig文件的<authorization>和<location>元素中配置
运行的时候他已经完成了。这种途径的最终用途淋漓尽致地体现在表单验证上。当用户访问受限资源的时候, 如果之前使用了表单验证,他会自动被重定向到指定的登录页面,在成功登录之后,用户被重定向回先前试图访问的受页面。
事件中,在登录页面上执行提交后,该页面会将用户重定向到网址重写指定的页面。假定当用户在浏览器上敲入/people/ScottMitchell.aspx地址,该地址是要被重定向到/info/employee.aspx?EmpID=1001的, 如果该Web应用程序设定使用表单验证,当用户开始访问/people/ScottMitchell.aspx的时候,该网址将重写指向/info/employee.aspx?EmpID=1001,接着
启动,如果需要的话将用户重定向到登录页面,用户登录后重定向到的页面将是/info/employee.aspx?EmpID=1001,这也是自从
同上类似,当把网址重写放在BeginRequest事件或者AuthenticateRequest事件中运行的时候,
也发现了网址重写指向的网址,这意味着如果在该应用程序的web.config文件中<location>节为特定的网址配置特定的授权地址的话,你得引用重写所指向的网址。
事件中运行,但是在使用这种方决URL授权和表单授权的异常时又引入了一个新的缺陷:文件授权会失效。当使用Windows验证的时候,
假定有一群用户并没有Windows级别的访问权限访问C:\inetpub\,当这些用户试图访问/info/employee.aspx?EmpID=1001的时候,他们会得到未授权的错误,如果我们把网址重写放到
验证该安全性设置的时候,他仍任人为被请求的文件是/people/ScottMitchell.aspx,而这时该网址已经被重写了,因此
会直接放行,让用户看到了网址重写指向的内容:/info/employee.aspx?Empid=1001。
事件中调用网址重写没有多大区别,如果使用表单验证方式并且不使用Windows验证方式的话,把网址重写放入
方法检查所请求的网址并决定是否需要调用网址重写。如果要调用网址重写的话则调用前文所述的已通过检查的
就开始被实例化。把网址重写放在这些事件场所的最后一个里头调用的时候,也会碰到相同的问题:文件授权将会失效。如果非要依赖于Windows验证和文件验证的时候,你可能得使用
下一章我们着眼于如何构建一个可重用的网址重写引擎,使用下文所提的这些示例均以真实案例作为参照,在作者主页上提供下载。先用用一个简单的网址重写的例子来探讨如何实现网址重写,紧接着将利用网址重写引擎则表达式的强大处理能力来展示真正“隐蔽”的网址重写技术!
我们来探讨一下在web.config中网址重写规则的配置节。首先必须在web.config文件中指出是否需要在
<add type=URLRewriter.ModuleRewriter,URLRewriter name=ModuleRewriter/>
<add verb=* path=*.aspx type=URLRewriter.RewriterFactoryHandler,URLRewriter />
不论配置使用<HttpModules>还是<httpHandlers>调用网址重写,除此之外还须配置网址重写规则,一条重写规则包括两项字符串:请求URL中的查找模式和针对该模式的匹配成功后的替换字符串。该信息在nfig文件中用下列标签描述:
<SendTo>String to replace pattern with </SendTo>
<SendTo>String to replace pattern with </SendTo>
每一条规则都用一个<RewriterRule>元素表示,以<LookFor>节表示查询模式,当查询模式发现匹配字符串时便用<SendTo>节表示的字符串进行替换。这些规则从上到下进行查询匹配,如果找到一个匹配则按此规则执行网址重写,并且停止查找。
配置<LookFor>节要使用正则表达式来进行字符串匹配和替换。(在此我们举一个例子来说明如何使用正则表达式来对字符串进行匹配和替换。)既然该查找模式是一个正则表达式,那么要注意避开对正则表达式保留字符串的直接使用。(正则表达式的保留字符串包括有:.,?,^,$,等等,可以通过在前面加上一个反斜线来引用这些保留字符,例如\.表示引用一个句点)
public abstract class BaseModuleRewriter : IHttpModule
public virtual void Init(HttpApplication app)
// WARNING! This does not work with Windows authentication!
app.AuthorizeRequest += new EventHandler(this.BaseModuleRewriter_AuthorizeRequest);
protected virtual void BaseModuleRewriter_AuthorizeRequest(object sender, EventArgs e)
HttpApplication app = (HttpApplication) sender;
protected abstract void Rewrite(string requestedPath, HttpApplication app);
protected override void Rewrite(string requestedPath, System.Web.HttpApplication app)
RewriterRuleCollection rules = RewriterConfiguration.GetConfig().Rules;
// Resolve the Url (convert ~ into the appropriate directory)
ntext.Request.ApplicationPath, rules[i].LookFor) + $;
// Create a regex (note that IgnoreCase is set
Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);
ntext.Request.ApplicationPath, re.Replace(requestedPath, rules[i].SendTo));
方法以获取nfig文件中的网址重写规则的设置为起始,它通过循环访问各条网址重写规则,每次均获取当前规则中的
如果发现一条匹配,将用当前规则的SendTo值对请求的径执行一个正则表达式替换,替换后的地址通过参数的形式传给
我们已经探讨了主要的部分,但是还有其它一些组件诸如将web.config文件中XML格式化了的网址重写规则反序列化至一个对象的类定义、通过
为了更好地示范网址重写引擎的运行,我们来建立一个 Web应用程序来实现简单的网址重写引擎。假定我们为一家在线销售各类商品的公司服务,这些产品划分为以下类别:
假定已经建立好一个名为ListProductsByCategoryID.aspx的ASP.NET页面文件,它通过查询参数获取一个分类编号,并根据此编号获取所有该分类下的所有商品。如果用户想浏览所销售的饮料类商品可以通过ListProductsByCategoryID.aspx?CategoryID=1来访问,如果用户想浏览所销售的日记本类商品可以通过ListProductsByCategoryID.aspx?CategoryID=4来访问。假定还有一个页面ListCategories.aspx,它列出所有代售商品的分类编号。
显然这里发现了一个网址重写的案例。对于用户来说他们所输入的地址不具有任何实际意义并且不具备任何“隐蔽性”,倒不如使用网址重写引擎让用户去访问/Products/Baverage.aspx地址,系统将该地址重写到ListProductsByCategoryID.aspx?CategoryID=1。我们可以在web.config文件中来完成网址重写任务:
<SendTo>~/ListProductsByCategoryID.aspx?CategoryID=1</SendTo>
很明显地看到,搜索用户访问的径是否匹配/Products/Baverage.aspx,如果匹配的话,则将网址重写到/ListProductsByCategoryID.aspx?CategoryID=1。
注意:你会发现<LookFor>节点中避免直接在“Baverage.aspx”中使用句点“.”是因为<LookFor>节点的值是正则表达式的匹配模式,在正则表达式中句点符号是一个特殊字符,它表示匹配任何一个字符,也就是说如果访问BaverageQaspx时也会发生匹配,为了避免发生这个句点引起的匹配我们得在该句点符号前面加上一个“\”,表示引用句点符号。
通过该规则定义,当用户访问/Products/Baverage.aspx文件的时候,他们将看到代售的饮料类商品列表信息。图3为访问/Products/Baverage.aspx地址时的浏览器截图,注意在浏览器中地址栏上显示的是用户输入的/Products/Baverage.aspx地址,但是实际访问的地址却是网址重写后的/ListProductsByCategoryID.aspx?CategoryID=1。(事实上,在服务器上根本就不存在/Products/Baverage.aspx文件!)
和/Products/Baverage.aspx类似,下一步我们添加其它分类的重写规则,只需简单地在nfig文件中<Rules>中在添加其他<RewriteRule>节即可。该演示完整的重写规则集合请参考下载文档的web.config文件中的定义。
为了让该网址更具有“隐蔽性”,如果让用户把/Products/Baverage.aspx后面Baverage.aspx一段截去,在浏览器中输入/Products/来浏览产品分类列表会更好一些。乍一看,这项任务微不足道,只需添加一条网址重写规则将/Products/映射到/ListCategories.aspx即可。然而这里有一个微妙之处,你必须先创建一个/Products/目录,并在里面放一个空文件Deult.aspx。
要认识为什么这些额外的步骤是必须的,先回顾一下前文。网址重写引擎是处于一级的,也就是说,如果ASP.NET没有获得处理请求的机会的话,网址重写引擎就不能对输入的网址请求作出判断。此外,IIS仅在请求文件包含相应扩展名时才将请求转交给ASP.NET引擎。如果用户访问/Products/,IIS并不知道其扩展名是什么,于是它检查该目录下的文件看是否包含有默认首页文件名(Deult.aspx,Deult.htm,Deult.asp,等等,这些文件名在IIS管理工具对话框中Web服务器属性对话框中的文档标签中定义。)当然,如果/Products/目录不存在的话,IIS将返回一个HTTP 404错误。
所以我们需要创建一个/Products/目录并在该目录下额外创建一个空文件Deult.aspx,IIS会检查该目录下的文件,发现有一个默认文件名Deult.aspx,于是将请求转交给ASP.NET,这样,网址重写引擎才能生效。
通过该规则,用户访问/Products/Deult.aspx或者访问/Products/都可以看到如图四所示的产品分类列表。
如果要重写的网址上包含有服务器端Web Form并执行数据回送,当该Web Form回送数据时会出真实的网址,也就是说,当用户访问/Products/Baverage.aspx时,浏览器上地址栏显示的也是/Products/Baverage.aspx,但是实际上是访问/ListProdutsByCategoryID.aspx?CategoryID=1的内容,如果ListProductsByCategoryID.aspx页面执行了数据回送的话,用户被数据回送定向给原始的/ListProductByCategoryID.aspx?CategoryID=1页面上,而不是/Products/Baverage.aspx页面。这虽然不是什么大问题,但是用户会觉察到点击一个按钮时网址发生了的变化,这也许会令人不安,因为如果出于网址安全的角度来说,直接把真实的网址出来了。
之所以发生这种现象的原因是当Web Form在呈现之时就明确地设置其action属性为当前
对象中文件径的值。当然,在Web Form呈现之时,从/Produts/Baverage.aspx到/ListProductsByCategoryID.aspx?CategoryID=1的网址重写就已经执行完毕了,这意味着
对象所汇报的是当前用户所访问的地址是/ListProductsByCategoryID.aspx?CategoryID=1。这么看来,只需让该服务器端表单在呈现之时不呈现action属性即可解决问题了。(对浏览器来说,如果不设置action属性的话,那么在提交的时候将使用其默认值。)
然而不幸的是该Web Form不会允许你指定action属性,也不会允许你通过设置一些属性来达到禁用呈现action属性的目的。得自行继承
public class Form:System.Web.UI.HtmlControls.HtmlForm
protected override void RenderAttributes(System.Web.UI.HtmlTextWriter writer)
@ Register TagPrefix = skm Namespace = ActionlessForm Assembly = ActionlessForm %>
你可以查看该文档相关下载中的ListProductsByCategoryID.aspx文件中的自定义Web Form,该下载已经提供了完整的项目文件包。
注意:如果你打算进行网址重写的地址不执行数据回送,则没有必要使用该自定义Web Form的类。
上一节简单网址重写的示例展示了如何通过新的网址重写规则来轻松地配置网址重写引擎,本节将通过出众的正则表达式来展示网址重写的强大威力。
时下正在流行Blog,很多人都拥有一个自己的Blog。不论你是否对Blog感到陌生,他们正在不断地更新自己的Blog页面,这些页面就像一个个人日记本一样。大多数Bloger只是简单地记录每天发生的事情,也有一些聚焦于某一主题,比如影评、球迷组织、电脑技术等。
Blog可以在任何地点由作者进行更新,更新次数可以是一天多次,也可以是一周一两次。在Blog页面上只显示最近10条更新,但事实上所有的Blog软件都提供了存档记录,访客可以阅读其历史记录。有了“隐蔽”的网址,Blog应用程序将变得更加强大。假定你通过/2004/02/14.aspx来查询自己的Blog上的文章,你会为阅读到2004年2月14日的Blog感到惊讶吗?此外你可能为了访问2004年2月所有的Blog而将该地址裁减为/2004/02/,要访问2004年所有的Blog,你可能会试着去访问/2004/。
在一个Blog的时候,如果将这种具有“隐蔽性”的网址提供给用户将会更好。实际上很多Blog引擎都提供了这种网址重写的功能,现在来看看这些是如何通过网址重写实现的。
首先,我们需要一个页面能够分别按照年、月、日分别显示Blog的内容。假定现在已经做好了一个页面文件ShowBlogContent.aspx,它能分别获取年、月、日的查询参数,要查看2004年2月14日所发的帖子,我们可以访问/ShowBlogContent.aspx?year=2004&month=2&day=14,要浏览2004年2月的数据可以访问/ShowBlogContent.aspx?year=2004&month=2,要查询2004年所有数据可以访问/ShowBlogContent.aspx?year=2004。(在下载文件中提供ShowBlogContent.aspx源代码。)
然后,当用户访问/2004/02/14.aspx时,我们需要将他访问的网址重写到/ShowBlogContent.aspx?year=2004&month=2&day=14上。这里需要制定网址重写规则:当指定访问年月日时、当指定访问年月时和当指定访问年时。
<LookFor>~/(d{4})/(d{2})/(d{2}).aspx</LookFor>
<SendTo>~/ShowBlogContent.aspx?year=$1month=$2day=$3</SendTo>
<LookFor>~/(d{4})/(d{2})/Deult.aspx</LookFor>
<SendTo><![CDATA[~/ShowBlogContent.aspx?year=$1&month=$2]]></SendTo>
<SendTo>~/ShowBlogContent.aspx?year=$1</SendTo>
这些网址重写规则展示了正则表达式的强大威力。第一条规则按照(\d{4})/(\d{2})/(\d{2})\.aspx模式进行查找,通俗的说,它查找是否包含匹配x/xx/xx.aspx格式的字符串,其中x表示数字,每一组数字必须用圆括号括起来,这样可以在相应<SendTo>节内引用圆括号内的匹配字符串。我们可以使用$1、$2、$3来分别引用前面匹配的圆括号组,其中$1,$2,$3分别表示所匹配的第一、第二、第三个圆括号组。
注意:由于nfig是XML格式的文档,所以在文本域内必须回避直接使用一些特殊字符,如:&,<和>符号等。在第一条网址重写规则的<SendTo>节中用&来表示引用&符号,在第二条网址重写规则的<SendTo>节中用<![CDATA[...]]>元素来表示其中所有的内容都是文本域,不再需要用转义字符来表示引用。这两种方法都可以实现同样的目的。
下面图五、图六、图七都显示出网址重写的运行状况。这些数据都真实地摘自作者的Blog,图五显示2003年11月7日的帖子,图六显示所有2003年11月的帖子,图七显示2003年所有帖子。
当IIS接收到对/2004/03/19.aspx的请求时,他发现文件扩展名.aspx,便将该请求转交给引擎处理,在ASP.NET 引擎中传递时,该地址被重写到/ShowBlogContent.aspx?year=2004&month=3&day=19,最后用户将看到该Blog上2004年3月19日所有的帖子,但是在用户访问/2004/03/时会发生什么呢?除非已经存在一个/2004/01/的目录,否则IIS将返回一个404错误,而且该目录下还必须要有一个默认页面Deult.aspx,IIS才能将请求转交给ASP.NET引擎处理。
通过这种方法你得手动为每一年的Blog创建一个年份的目录并在该年份下放置一个默认文件Deult.aspx,而且还得在该年份目录下创建每一月的目录,从01、02、...、12,每一个目录下也要防止一个默认文件Deult.aspx。(回想前面的例子,为了将/Products/重写到/ListCategories.aspx也是要建立一个/Products/目录并放置一个默认Deult.aspx文件。
很明显,这样创建目录结构的过程是很痛苦的。解决这种问题的一个办法就是设置IIS将所有接收的请求都转交给ASP.NET引擎来处理,这种方法,甚至连访问这种地址/2004/04/,IIS都如实地将其转交给ASP.NET引擎处理,这种方法造成ASP.NET引擎得处理所有传入的请求,包括css文件,图片文件、Javascript文件以及Flash文件等等。
关于对所有类型文件的处理的详细讨论已经超出了本书范围。有关在ASP.NET Web应用程序中使用这些技术的例子请访问.Text 这个开源的Blog。.Text 可以通过配置将所有请求都转交给ASP.NET处理。它使用了一个自定义的
的属性时也修改了所请求的文件和径。实际得到的效果就是在用户访问其特有的网址的时候,他实际却是在服务器端请求另一个与此不同的网址。
当然,在ASP.NET一级的网址重写中,只有在IIS成功地将请求转交给ASP.NET引擎后才能成功地执行,当用户请求一个扩展名为.aspx的文件时这很自然地发生。然而,如果要让用户输入一个实际并不存在的网址,通过网址重写到另一个存在的aspx页面,你必须为该请求创建相应的目录和默认的Deult.aspx页面,除非配置IIS让它把所有的请求都转交给IIS处理,但是这种方式盲目地将所有请求都转交给了ASP.NET引擎。
推荐:
网友评论 ()条 查看