本文转自:http://www.cnblogs.com/showker/archive/2010/01/11/1644062.html
前言:为什么转载这篇文章?因为它有思考有实践。最近因为业务的需要,要对Url进行重写,其实也不是重写,也就是像在php中非常容易实现的隐藏.php后缀一样来隐藏.aspx后缀。搜索不少文章,都提到URL重写,但是对于如何隐藏.aspx后缀描述不清。经过不懈搜索搜到这篇文章,按照其步骤,实现了如test.aspx,直接用test访问.我实践后想说的,实现隐藏.aspx,必须要在IIS里配置.*的隐射。而且伴随在IIS中配置了.*的隐射后会带来一系列问题。我目前碰到的有
0、在IIS中配置好.*的隐射后,还必须在handler中配置
<add verb="*" path="*" type="URLRewriter.RewriterFactoryHandler, URLRewriter" />
否则会出现404错误
1、默认文档无效的问题。比如输入http://192.168.1.1/提示找不到"/",按理应该跳转到默认文档比如index.html。这时我们需要在规则里添加
<!--因handlers的原因导致默认文档失效如http://localhost/到不了index.html)-->
<RewriterRule>
<LookFor>~(/?)$</LookFor>
<SendTo>~/index.html</SendTo>
</RewriterRule>
2、html文件无法打开的问题。这个网上有网友碰到过,解决方法是
<compilation debug="true" >
<!-- 加上此节点,保证原本就是.html类型的文件能正常访问 -->
<buildProviders>
<add extension=".html" type="System.Web.Compilation.PageBuildProvider" />
</buildProviders>
</compilation>
附件是我现在实现了无后缀名的web.config文件及使用的urlrewritting的dll,供大家参考。
转载开始
学习正则表达式 小有一段时间了,但就现在的应用情况来看,还是处于初级的基础应用水平,通过简单的使用正则,我觉得每当有一个新问题、一种新需求出现时,都需要考虑在正 则如何实现的范围内,正则的格式或实现方法可能都会需要灵活的变化,因为在正则的使用上有可能需要考虑地域、文化、甚至是国际条例等等当然这是个特例,所以在设计正则表达式前,是需要尽可能的分析好要匹配或是处理的项,以便在之后的实际应用中不会因为一个类似项的出现而无法实现原有的需求匹配、替换),同时,一个设计很好的表达式在可读性,甚至是效率上都会明显的区别与设计过于复杂、而实现方式又不好的那些。所以从分析需求、应用语法,到测试正则,这是基本的正则实现方法。
由于正则的简要的语法和相关事项在网络上都有详细的说明,这里不在赘述,下面我通过结合个人的实际应用,来简单的说明它的应用,当然涉及的正则式可能在某些地方也很是不足,但能得到大家的意见、指导……也对我以后的学习会有良好的推动作用:)。参阅下面下述文档前,如果还有时间,建议可以先看下Microsoft网站的一篇文章,因为在表述上是通过一个系统的功能实现来进行的,且涉及URLRewriting。《URLRewriteing的实现方法》
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/urlrewriting.asp
一、 实现URLRewrite的方法
URLRewrite的实现,如果看过Microsoft的文章,则可以大致的了解其实现原理,然而它的实现方法也不仅仅是文中所提到的。
以下为个人在实际应用中实现URLRewrite的方法:
1、应用IIS进行配置(IIS5.0):
在IIS中找到应用程序站点或程序对应的虚拟目录,右击/属性/目录/应用程序配置/配置/应用程序映射选项/,然后选择添加映射,在可执行文件框中浏览aspnet_isapi.dll文件(一般为C:\WINNT\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll),扩展名输入.*(如果针对.html的可直接输入单个扩展即可),动作设为“POST,GET”(为减少不必要的资源耗费,不用设置为全部动作),其他的默认即可。之所以这样做,是要把请求判断权交给ASPNET处理,而不是IIS去刷选,所以这个映射是必要的。完成这里的操作后,继续……
由于用户请求连接时Application_BeginRequest()函数会被触发,所以只需要在这里判断客户端提交的请求就可以了,这就正是上面将IIS筛选权给ASPNET的原因所在。
2、要实现的需求情况:
需求信息:
1、 处理静态页面.HTML到.ASPX页面的映射
2、 实现按照2006/8/4(/)或2006/08/06(/)形式访问站点时,访问到诸如.aspx?log_Year=2006&log_Month=8&log_Day=4的请求页面
3、 2006/到.aspx? log_Year=2006的映射
4、 2006/8(/)或2006/08(/)到.aspx? log_Year=2006&log_Month=8的映射
5、 同步需要处理图片、CSS、验证码路径的映射
6、 系统文章访问按照“L数字.html”形式访问,映射.aspx?logID=数字
7、 文章分类按照“C数字.html”形式访问,映射.aspx?cateID=数字
8、 编辑文章时按照“E数字.html”形式访问,映射.aspx?edit=数字
9、 ……
3、实现方式:
有两种方式通过正则进行处理,一方面可以直接在后台类代码里写正则匹配,还可以将编写的正则放入指定的外部文件中进行调用分析,诸如“Rewrite.config”。
在第一种方法实现时,可以在Application_BeginRequest()触发时进行判断处理,可改为任何所需要的访问方式,无需第三方DLL的支持。
4、匹配语法&实现:
string strNewUrl;//存放处理后的转向URL信息
/**//*这里只给一个示范,其他需求的实现类似,只需要更改对应的正则式,在下面的方法中将详细的说明其实现*/
if (Regex.IsMatch(strRawUrl, @"(w+).html", RegexOptions.IgnoreCase))
{
strNewUrl = Regex.Replace(strRawUrl, @"(w+).html", @"$1.aspx", RegexOptions.IgnoreCase);
HttpContext.Current.RewritePath( strNewUrl );
}
/**//*处理图片、样式表、验证码路径类似……*/
第二种方法则是通过读取、分析外部配置文件,从而获得正则处理的输入和格式串等信息,当然这里也可以直接在默认的Web.config文件里写,我将它放到了单独的Rewrite.config文件里,格式如下:
<RewriterConfig>
<Rules>
<RewriterRule><!--基本的静态页面访问 default.html blogpost.html-->
<LookFor>(w+).html</LookFor>
<SendTo>$1.aspx</SendTo>
</RewriterRule>
/*其他的匹配类似 */
</Rules>
</RewriterConfig>
上面的需求可能比较简单,不是需要编写大段的正则代码,所以在逻辑上只要一步一步的设计下去即可。
(1)、从HTML到ASPX的映射,这个比较简单,只是需要将.HTML的后缀映射为ASPX即可。
<LookFor>(w+).html</LookFor>
<SendTo>$1.aspx</SendTo>
</RewriterRule>
上面的()号,表示一个捕获组,匹配的字符作为最终匹配的部分
(2)、2006/8/4(/)或2006/08/06(/)形式访问站点时,映射为
.aspx?log_Year=2006&log_Month=8&log_Day=4的请求
这里的实现和上面一样,需要匹配特定的symbol(数字、符号),这里有两种情况需要考虑在内月份和具体的天,有可能是单个数字,也可能是两个数字组成,所以利用简单的匹配项,构建如下:
(\d{4})/(\d{1,2})/(\d{1,2})(/?)$
{1,2}表示了匹配前面的内容项时,该项是1到2个元素组成,$字符指示了至此该匹配串结束,后面不会有其他任何字符元素,同上,()组将作为最终输出的匹配项。
传递匹配值如下:
default.aspx?log_Year=$1&log_Month=$2&log_Day=$3
//\d表示的是0—9的数字,{4}表示前匹配项有4个元素
// /?表示“/”字符可有可无,?则表示前面匹配项为1次或0次出现
//&表示的是实际要用的“&”字符,它作为URL参数的连接项,在这里需要进行转换,否则读取时将会出错。
(3)、2006/到.aspx? log_Year=2006的映射
实现方式如上,(\d{4})/(\d{1,2})(/?)$
(4)、同步需要处理图片、CSS、验证码的相对路径问题
由于在表达式匹配后,相对的图片、CSS,甚至动态生成的图片验证码都将不会正常显示,因为匹配将替换页面的默认路径,比如输入2006/来访问时,图片的相对路径也将变为http://www.XXX.cn/blog/2006/images/…….gif,而不是原来的http://www.XXX.cn/blog/images/…….gif,所以要去实现这样的转换,为减少正则的复杂性,我将各种情况进行了单独处理,
2006/images :(\d{4})/([images|styles]+)/(.+)
引用:$2/$3
中间的“[images|styles]”表示没有用通用的字符去匹配,因为还可能有其他的类似目录,为防止替换,这里我是这样限制的,“(.+)”这里表示的是只要包含前面的images|styles路径信息则都会匹配的,而不看它后面的串信息。
2006/6/19/images: (\d{4})/(\d{1,2})/(\d{1,2})(/?)([images|styles]+)/(.+)
引用: $5/$6
同上
2006/6/images: (\d{4})/(\d{1,2})/([images|styles]+)/(.+)
引用: $3/$4
同上
(5)、系统文章浏览按照“L数字.html”形式,文章分类列表信息按照“C数字.html”访
问,编辑文章时按照“E数字.html”访问……等, 这里和上面的静态页面匹配是同用的。
首先看文章浏览“L数字.html”,这里的HTML会被自动的匹配为ASPX,而“数字”也将会被匹配,并进行处理映射处理。如下:
<SendTo>/blogview.aspx?logID=$4&page=1</SendTo>
由上面的几种情况在分开处理时是较为简单的,当然还可以将它们放到一个表达式中进行匹配处理,这在实现上相对复杂了一些,之前也没有时间去检查、修改,所以有兴趣的朋友可以思考下哦J。
在实现上述正则的编写后,需要在后台类里进行处理(提取、正则匹配),和第一种方式相同,在应用程序开始请求的时候处理,Application_BeginRequest编码如下:
XPathDocument myXPathDocument = new XPathDocument(path);
XPathNavigator myXPathNavigator = myXPathDocument.CreateNavigator();
XPathNodeIterator myXPathNodeIterator = myXPathNavigator.Select ("//RewriterRule");
while (myXPathNodeIterator.MoveNext())
{
//循环遍历Rewrite文件里的所有节点信息,对单条匹配规则也逐条处理(略)
//获取LookFor、SendTo后,传递给后台正则需要匹配的串、格式等
//同时重写路径信息
strNewUrl = Regex.Replace(strRawUrl,oldString,newString,RegexOptions.IgnoreCase);
HttpContext.Current.RewritePath( strNewUrl );
}
上面简单的说明了正则的一个实际应用的例子,实现的并不是复杂,关键是写正则前的分析与多种情况的考虑,限于篇幅,下面给出分布实现的几个方面,如下:
<RewriterConfig>
<Rules>
<RewriterRule><!--基本的静态页面访问 default.html blogpost.html-->
<LookFor>(w+).html</LookFor>
<SendTo>$1.aspx</SendTo>
</RewriterRule>
<!--====以下格式不能合并完成,因为不同请求不同路径===-->
<RewriterRule><!--2006/6/19的格式访问2006/6/19(/?)-->
<LookFor>(d{4})/(d{1,2})/(d{1,2})(/?)$</LookFor>
<SendTo>default.aspx?log_Year=$1&log_Month=$2&log_Day=$3</SendTo>
</RewriterRule>
<RewriterRule><!--重写图片和样式表路径2006/6/19/images-->
<LookFor>(d{4})/(d{1,2})/(d{1,2})(/?)([images|styles]+)/(.+)</LookFor>
<SendTo>$5/$6</SendTo>
</RewriterRule>
<RewriterRule><!--重写验证码路径2006/6/19/checkcode.aspx-->
<LookFor>(d{4})/(d{1,2})/(d{1,2})(/?)checkcode.aspx</LookFor>
<SendTo>checkcode.aspx</SendTo>
</RewriterRule>
<RewriterRule><!--重写通过2006/6/19访问后 2006/6/19/blogview.aspx?logID=……等-->
<LookFor>(d{4})/(d{1,2})/(d{1,2})(/?)(w+).aspx</LookFor>
<SendTo>$5.aspx</SendTo>
</RewriterRule>
<!--============================================-->
<!--只请求blog目录时的处理,交给ASPNET处理,默认文件不能访问的处理-->
<!--http://www.mcan.cn/blog(/)-->
<RewriterRule><!--blog/ or blog -->
<LookFor>(.*)/blog(/?)$</LookFor>
<SendTo>$1/blog/default.aspx</SendTo>
</RewriterRule>
<RewriterRule>
<LookFor>^(/?)images/(.+)</LookFor>
<SendTo>/blog/images/$2</SendTo>
</RewriterRule>
<!--============================================-->
<RewriterRule><!--分类访问-->
<LookFor>/(d{4})?/?(d{1,2})?/?(d{1,2})?/?c(d+).html</LookFor>
<SendTo>/default.aspx?cateID=$4</SendTo>
</RewriterRule>
<RewriterRule><!--单个日志访问-->
<LookFor>/(d{4})?/?(d{1,2})?/?(d{1,2})?/?log(d+).html</LookFor>
<SendTo>/blogview.aspx?logID=$4&page=1</SendTo>
</RewriterRule>
<RewriterRule><!--2006/6/6/default.html 类似的形式 非c2、log2、edit2等-->
<LookFor>/(d{4})?/?(d{1,2})?/?(d{1,2})?/?([a-zA-Z]+).html</LookFor>
<SendTo>/$4.aspx</SendTo>
</RewriterRule>
<RewriterRule><!--单个日志编辑-->
<LookFor>/(d{4})?/?(d{1,2})?/?(d{1,2})?/?edit(d+).html</LookFor>
<SendTo>/blogedit.aspx?logID=$4</SendTo>
</RewriterRule>
</Rules>
</RewriterConfig>
要真正的学好正则、应用正则的确是很不容易,所以在平时的学习中还是要经过大量的实践与思考,我也会积极的向各位同仁请教、学习,希望大家不吝赐教!
附件web.config及所使用的urlrewritting的dll