欢迎您访问我爱IT技术网,今天小编为你分享的编程技术是:【在ASP.NET中用MSDNURLRewriting实现Url Rewriting】,下面是详细的讲解!
在ASP.NET中用MSDNURLRewriting实现Url Rewriting
<RewriterConfig>
<Rules>
<!—- Rules for products lister -->
<RewriterRule>
<LookFor>~/Products/Baverage.aspx</LookFor>
<SendTo
<RewriterConfig>
<Rules>
<!—- Rules for products lister -->
<RewriterRule>
<LookFor>~/Products/Baverage.aspx</LookFor>
<SendTo>~/ListProductsByCategoryID.aspx?CategoryID=1</SendTo>
</RewriterRule>
</Rules>
</RewriterConfig>很明显地看到,搜索用户访问的路径是否匹配/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类似,下一步我们添加其它分类的重写规则,只需简单地在web.config文件中<Rules>中在添加其他<RewriteRule>节即可。该演示完整的重写规则集合请参考下载文档的web.config文件中的定义。
为了让该网址更具有“隐蔽性”,如果让用户把/Products/Baverage.aspx后面Baverage.aspx一段截去,在浏览器中输入/Products/来浏览产品分类列表会更好一些。乍一看,这项任务微不足道,只需添加一条网址重写规则将/Products/映射到/ListCategories.aspx即可。然而这里有一个微妙之处,你必须先创建一个/Products/目录,并在里面放一个空文件Default.aspx。
要认识为什么这些额外的步骤是必须的,先回顾一下前文。网址重写引擎是处于ASP.NET一级的,也就是说,如果ASP.NET没有获得处理请求的机会的话,网址重写引擎就不能对输入的网址请求作出判断。此外,IIS仅在请求文件包含相应扩展名时才将请求转交给ASP.NET引擎。如果用户访问/Products/,IIS并不知道其扩展名是什么,于是它检查该目录下的文件看是否包含有默认首页文件名(Default.aspx,Default.htm,Default.asp,等等,这些文件名在IIS管理工具对话框中Web服务器属性对话框中的文档标签中定义。)当然,如果/Products/目录不存在的话,IIS将返回一个HTTP 404错误。
所以我们需要创建一个/Products/目录并在该目录下额外创建一个空文件Default.aspx,IIS会检查该目录下的文件,发现有一个默认文件名Default.aspx,于是将请求转交给ASP.NET,这样,网址重写引擎才能生效。
<RewriterRule>
<LookFor>~/Products/Default.aspx</LookFor>
<SendTo>~ListCategories.aspx</SendTo>
</RewriterRule>通过该规则,用户访问/Products/Default.aspx或者访问/Products/都可以看到如图四所示的产品分类列表。
图四.在网址上添加“隐蔽性”
1.12.4.处理回送数据
如果要重写的网址上包含有服务器端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属性为当前Request对象中文件路径的值。当然,在Web Form呈现之时,从/Produts/Baverage.aspx到/ListProductsByCategoryID.aspx?CategoryID=1的网址重写就已经执行完毕了,这意味着Request对象所汇报的是当前用户所访问的地址是/ListProductsByCategoryID.aspx?CategoryID=1。这么看来,只需让该服务器端表单在呈现之时不呈现action属性即可解决问题了。(对浏览器来说,如果不设置action属性的话,那么在提交的时候将使用其默认值。)
然而不幸的是该Web Form不会允许你指定action属性,也不会允许你通过设置一些属性来达到禁用呈现action属性的目的。得自行继承System.Web.HtmlControls.HtmlForm这个类,并重载该类的RenderAttribute()方法,明确指出该类不呈现acton属性。
感谢继承这个强大的功能,使得我们很简单就获取了HtmlForm这个类下所有的功能定义,只需少量几行代码就达到所需目的,完整代码如下所示:
namespace ActionlessForm

{
public class Form:System.Web.UI.HtmlControls.HtmlForm
{
protected override void RenderAttributes(System.Web.UI.HtmlTextWriter writer)
{
writer.WriteAttribute("name",this.Name);
base.Attributes.Remove("name");
writer.WriteAttribute("method",this.Method);
base.Attributes.Remove("method");
this.Attributes.Render(writer);
base.Attributes.Remove("action");
if (base.ID!=null)
{
writer.WriteAttribute("id",this.ClientID);
}
}
}
}
对RenderAttributes()方法重载的代码包含了原类HtmlForm的RenderAttributes()方法全部的代码内容,只是简单地去掉了设置action属性这一节。(我参考了Lutz Roeder的Reflecter一文中类HtmlForm的源代码)
当创建并编译了这个类后,将其添加到引用目录即可在该ASP.NET Web应用程序中使用。为了将原有HtmlForm类替换,只需简单地在页面顶部添加下列代码:

<%
@ Register TagPrefix="skm" Namespace="ActionlessForm" Assembly="ActionlessForm"%>然后将<Form runat=”server”>标签替换为
<skm:Form id="Form1" method="post" runat="Server">并将结束标记</Form>替换为
<skm:Form>你可以查看该文档相关下载中的ListProductsByCategoryID.aspx文件中的自定义Web Form,该下载已经提供了完整的Visual Studio.NET项目文件包。
注意:如果你打算进行网址重写的地址不执行数据回送,则没有必要使用该自定义Web Form的类。
1.13. 创建真正“隐蔽”的网址
上一节简单网址重写的示例展示了如何通过新的网址重写规则来轻松地配置网址重写引擎,本节将通过出众的正则表达式来展示网址重写的强大威力。
时下正在流行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上。这里需要制定三条网址重写规则:当指定访问年月日时、当指定访问年月时和当指定访问年时。
<RewriterConfig>
<Rules>
<!-- Rules for Blog Content Displayer -->
<RewriterRule>
<LookFor>~/(d{4})/(d{2})/(d{2}).aspx</LookFor>
<SendTo>~/ShowBlogContent.aspx?year=$1&month=$2&day=$3</SendTo>
</RewriterRule>
<RewriterRule>
<LookFor>~/(d{4})/(d{2})/Default.aspx</LookFor>
<SendTo><![CDATA[~/ShowBlogContent.aspx?year=$1&month=$2]]></SendTo>
</RewriterRule>
<RewriterRule>
<LookFor>~/(d{4})/Default.aspx</LookFor>
<SendTo>~/ShowBlogContent.aspx?year=$1</SendTo>
</RewriterRule>
</Rules>
</RewriterConfig>这些网址重写规则展示了正则表达式的强大威力。第一条规则按照(\d{4})/(\d{2})/(\d{2})\.aspx模式进行查找,通俗的说,它查找是否包含匹配xxxx/xx/xx.aspx格式的字符串,其中x表示数字,每一组数字必须用圆括号括起来,这样可以在相应<SendTo>节内引用圆括号内的匹配字符串。我们可以使用$1、$2、$3来分别引用前面匹配的圆括号组,其中$1,$2,$3分别表示所匹配的第一、第二、第三个圆括号组。
注意:由于web.config是XML格式的文档,所以在文本域内必须回避直接使用一些特殊字符,如:&,<和>符号等。在第一条网址重写规则的<SendTo>节中用&来表示引用&符号,在第二条网址重写规则的<SendTo>节中用<![CDATA[...]]>元素来表示其中所有的内容都是文本域,不再需要用转义字符来表示引用。这两种方法都可以实现同样的目的。
下面图五、图六、图七都显示出网址重写的运行状况。这些数据都真实地摘自作者的Blog(http://ScottOnWritting.net),图五显示2003年11月7日的帖子,图六显示所有2003年11月的帖子,图七显示2003年所有帖子。
图五.显示2003年11月7日的帖子
图六. 显示2003年11月所有的帖子
图七. 显示2003年所有的帖子
注意:要使用网址重写引擎,强烈推荐在<LookFor>节中使用正则表达式。如果你对正则表达式不是很熟悉,可以先阅读作者本人写的一篇文章An Introduction to Regular Expressions,此外还可以在RegexLib.com 上查询常用的正则表达式,或把你自己设计的正则表达式提交到该站点共享使用。
1.14. 创建必须的目录结构
当IIS接收到对/2004/03/19.aspx的请求时,他发现文件扩展名.aspx,便将该请求转交给ASP.NET引擎处理,在ASP.NET 引擎中传递时,该地址被重写到/ShowBlogContent.aspx?year=2004&month=3&day=19,最后用户将看到该Blog上2004年3月19日所有的帖子,但是在用户访问/2004/03/时会发生什么呢?除非已经存在一个/2004/01/的目录,否则IIS将返回一个404错误,而且该目录下还必须要有一个默认页面Default.aspx,IIS才能将请求转交给ASP.NET引擎处理。
通过这种方法你得手动为每一年的Blog创建一个年份的目录并在该年份下放置一个默认文件Default.aspx,而且还得在该年份目录下创建每一月的目录,从01、02、...、12,每一个目录下也要防止一个默认文件Default.aspx。(回想前面的例子,为了将/Products/重写到/ListCategories.aspx也是要建立一个/Products/目录并放置一个默认Default.aspx文件。
很明显,这样创建目录结构的过程是很痛苦的。解决这种问题的一个办法就是设置IIS将所有接收的请求都转交给ASP.NET引擎来处理,这种方法,甚至连访问这种地址/2004/04/,IIS都如实地将其转交给ASP.NET引擎处理,这种方法造成ASP.NET引擎得处理所有传入的请求,包括css文件,图片文件、Javascript文件以及Flash文件等等。
关于对所有类型文件的处理的详细讨论已经超出了本书范围。有关在ASP.NET Web应用程序中使用这些技术的例子请访问 .Text 这个开源的Blog。.Text 可以通过配置将所有请求都转交给ASP.NET处理。它使用了一个自定义的HttpHandler来处理所有类型的文件类型,这个自定义的HttpHandler可以识别并判断如何处理所有的文件类型。(图像文件、CSS文件等等。)
1.15. 结束语
本文探讨了通过类HttpContext类的RewriteUrl()方法来实现ASP.NET一级的网址重写,正如我们所看到那样,RewriteUrl()方法在修改这个特有的HttpContext的Request的属性时也修改了所请求的文件和路径。实际得到的效果就是在用户访问其特有的网址的时候,他实际却是在服务器端请求另一个与此不同的网址。
网址重写不但可以在HttpModule中执行,也可以在HttpHandler中运行。本文我们探讨了在一个HttpModule中执行网址重写,也研究了一下网址重写在ASP.NET中的各个不同场所的情况。
当然,在ASP.NET一级的网址重写中,只有在IIS成功地将请求转交给ASP.NET引擎后才能成功地执行,当用户请求一个扩展名为.aspx的文件时这很自然地发生。然而,如果要让用户输入一个实际并不存在的网址,通过网址重写到另一个存在的aspx页面,你必须为该请求创建相应的目录和默认的Default.aspx页面,除非配置IIS让它把所有的请求都转交给IIS处理,但是这种方式盲目地将所有请求都转交给了ASP.NET引擎。
1.16. 参考
本文源代码下载地址:http://download.microsoft.com/download/0/4/6/0463611e-a3f9-490d-a08c-877a83b797cf/MSDNURLRewriting.msi
《深入研究IIS与ASP.NET》(Inside IIS and ASP.NET) 作者:Michele Leroux Bustamante
工作参考:网址重写是一个颇受欢迎的主题,不论是ASP.NET还是其他竞争对手都对其表示出巨大的关注。例如:Apache Web Server提供了一个叫做mod_rewriting的模块,mod_rewriting是个功能完善的网址重写引擎,它提供基于HTTP 头信息和服务器参数环境的网址重写功能,甚至还提供用正则表达式来创建网址重写规则。有关mod_rewriting更多信息请参考A User's Guide to URL Rewriting with the Apache Web Server《Apache Web Server网址重写用户向导》。
这里有相当数量的关于ASP.NET级别下网址重写的文章:
Rewrite.NET - A URL Rewriting Engine for .NET探讨模拟mod_rewriting的正则表达式描述的网址重写规则来实现ASP.NET下网址重写;
URL Rewriting With ASP.NET提供对ASP.NET下网址重写能力的总的概述;
Ian Griffiths有一个Blog,上面有许多有关在ASP.NET中实现网址重写的建议,比如本文所提到的考虑到数据回送时的做法;
Fabrice Marguerie和Jason Salas都各有一个Blog,在上面可以找到有关将ASP.NET网址重写来推动搜索引擎的查找替换的文章。
(Fabrice Marguerie: http://weblogs.asp.net/fmarguerie/archive/2003/12/24/45712.aspx)
(Jason Salas: http://weblogs.asp.net/jasonsalas/archive/2003/12/14/43404.aspx)
</RewriterRule>
</Rules>
</RewriterConfig>关于在ASP.NET中用MSDNURLRewriting实现Url Rewriting的用户互动如下:
相关问题:
答: >>详细
相关问题:
答: >>详细
相关问题:
答: >>详细
