使用URL回写是一种对搜索引擎友好的方式,也便于直观地知道URL所对应的含义.
比如我的博客现在就用了URL回写: http://www.ttpretty.com/blog/
网上类似的内容比较多,现在就来一步一步自己实现一个URL回写….
首先选择URL回写的处理位置,是位于HTTPMoudle里面还是位于HTTPHandler里面.一直没搞清楚两者性能有什么区别,或许与它们加载的位置有区别,在这里我用的是HTTPMoudle.
考虑到灵活性,我们假定在web.config中允许用户自定义回写的方式.
那么我们先来创建一个配置类.在ASP.net中,实现自动从web.config中取出SectionGroup的方法是使用 System.Configuration.IConfigurationSectionHandler 接口,这个接口只有一个方法,就是 Create(),用来返回一个格式化的自定义对象.
函数原型如下:
Public Function Create(ByVal parent As Object, ByVal configContext As Object, ByVal section As System.Xml.XmlNode) As Object
其中的section就是表示配置节所在区段的XML节点树了.
我们最终实现的类如下,具体定义请参考注释:
NamespaceFS.HttpServer
PublicClassUrlRewriterConfig
ImplementsSystem.Configuration.IConfigurationSectionHandler'实现接口
'下面这个是接口的唯一方法,用于创建自定义的对象
PublicFunctionCreate(ByValparentAsObject,ByValconfigContextAsObject,ByValsectionAsSystem.Xml.XmlNode)AsObjectImplementsSystem.Configuration.IConfigurationSectionHandler.Create
'在这个例程中,其实返回的是一个 System.Collections.Specialized.NameValueCollection 对象.
DimrAsNewSystem.Collections.Specialized.NameValueCollection
Dimn,mfAsSystem.Xml.XmlNode
Dimsf,stAsString
ForEachnInsection.ChildNodes'遍历整个区域的所有子节点
Ifn.Name="add"Then'如果子节点的名字是add,那么就判定这是一条回写的规则,进行读取
sf=Nothing
st=Nothing
'这里,规定一条规则包含两个节点,分别为searchfor和mapto,分别表示要匹配的规则,和回写后的URL格式
'由于涉及到正则,因此需要你对正则表达式的格式有充分的了解.
ForEachmfInn.ChildNodes
Ifmf.Name="searchfor"Then
sf=mf.InnerText
ElseIfmf.Name="mapto"Then
st=mf.InnerText
EndIf
Next
'如果两个值都不为空才会加入列表,否则是要忽略的.
IfNot(String.IsNullOrEmpty(sf))AndAlsoNot(String.IsNullOrEmpty(st))Then
r(sf)=st
EndIf
EndIf
Next
Returnr
EndFunction
EndClass
EndNamespace
OK………..下面我们来创建HttpMoudle,具体的请参考注释.代码如下:
NamespaceFS.HttpServer
PublicClassUrlRewriter
ImplementsIHttpModule'实现接口IHttpModule
PublicSubDispose()ImplementsSystem.Web.IHttpModule.Dispose
EndSub
'这是接口的初始化过程,我们在这里使用AddHandler方法来捕捉请求的BeginRequest方法.
'由于在请求前就开始回写,所以效率还是比较高的
PublicSubInit(ByValcontextAsSystem.Web.HttpApplication)ImplementsSystem.Web.IHttpModule.Init
AddHandlercontext.BeginRequest,AddressOfRewrite
EndSub
'具体的回写实现逻辑
PublicSubRewrite(ByValsenderAsObject,ByValeAsEventArgs)
DimmatcAsSystem.Collections.Generic.Dictionary(OfSystem.Text.RegularExpressions.Regex,String)
DimconAsHttpApplication=CType(sender,HttpApplication)
DimregAsSystem.Text.RegularExpressions.Regex
'获得缓存中的回写正则表达式列表.由于创建/解析正则表达式是一个有点消耗性能的过程,因此
'为了提高性能,在一次性创建正则表达式列表后加入缓存,以提高每次请求的响应速度.这只是一个理论,
'寡人的小站因为流量太小所以根本没法测试效果到底怎么样.
matc=con.Context.Cache.Item("$FantasyStudio.UrlRewriteConfig_"&con.Request.ApplicationPath)
IfmatcIsNothingThen
'创建一个新的正则表达式集合对象
matc=NewSystem.Collections.Generic.Dictionary(OfSystem.Text.RegularExpressions.Regex,String)
'下面两行是为了从web.config中读取 FantasyStudio.UrlMapper 配置节而创建的.
DimcollAsSystem.Collections.Specialized.NameValueCollection
coll=System.Web.Configuration.WebConfigurationManager.GetWebApplicationSection("FantasyStudio.UrlMapper")
DimsearchforAsString
'创建每个正则表达式对象,然后加入列表中
ForEachsearchforIncoll.AllKeys
reg=NewSystem.Text.RegularExpressions.Regex(searchfor,RegexOptions.IgnoreCaseOrRegexOptions.SinglelineOrRegexOptions.CultureInvariantOrRegexOptions.Compiled)
matc.Add(reg,coll(searchfor))
Next
'加入缓存.
con.Context.Cache.Add("$FantasyStudio.UrlRewriteConfig_"&con.Request.ApplicationPath,matc,Nothing,System.Web.Caching.Cache.NoAbsoluteExpiration,System.Web.Caching.Cache.NoSlidingExpiration,System.Web.Caching.CacheItemPriority.Normal,Nothing)
EndIf
'从这里开始,是回写工作的开始
DimmatAsSystem.Text.RegularExpressions.Match
Dimrawurl=con.Request.Url.PathAndQuery
DimmaptoAsString
mapto=Nothing
'开始尝试匹配每个正则表达式,这是一个很简单的遍历过程
ForEachregInmatc.Keys
mat=reg.Match(rawurl)
IfNotmatIsNothingAndAlsomat.SuccessThen
'哦,这里就匹配成功了,那么就根据匹配结果获得一个回写的目标地址,然后退出循环
mapto=mat.Result(matc(reg))
ExitFor
EndIf
Next
'如果不是空字符串,则说明回写成功了,那么就调用 Context.RewritePath() 方法来回写地址
'至此,完工
IfNotString.IsNullOrEmpty(mapto)Then
con.Context.RewritePath(mapto)
EndIf
EndSub
EndClass
EndNamespace
OK….建工程,编译,然后放到网站的bin目录中.
现在打开web.config文件,加入配置节.
1.在<configSections>中加入配置段说明:
<sectionname="FantasyStudio.UrlMapper"type="FS.HttpServer.UrlRewriterConfig"/>
2.在</configSections>后加入回写规则的配置段.如下:
<FantasyStudio.UrlMapper>
<!--
URL Rewriter
-->
<add>
<searchfor>(?<basedir>.*?)/Blogger/(?<uid>w+?)/(?<verb>Catalog|Date|Index|Show|Trackback|Rss2|Search)([_]?)(?<id>[^.]*).(?<fileext>w*)</searchfor>
<mapto>${basedir}/Blog.aspx?action=${verb}&fileext=${fileext}&user=${uid}&id=${id}</mapto>
</add>
<add>
<searchfor>(?<basedir>.*?)/Blogger/(?<uid>w+?)/Admin_(?<id>[^.]*).(?<fileext>w*)</searchfor>
<mapto>${basedir}/Admin/Index.aspx?fileext=${fileext}&user=${uid}&id=${id}</mapto>
</add>
</FantasyStudio.UrlMapper>
3.哦,上面的是我的博客里面的规则,做例子的.现在加入HttpMoudle,在<system.web>下的<httpModules>节点中加入钩子:
4.恩…应该完工了,现在保存配置,然后..刷新浏览器.祝你好运 🙂
<addname="FS.HttpServer.UrlRewriter"type="FS.HttpServer.UrlRewriter"/>
—————-
编译好的DLL可以在这里下载: http://www.ttpretty.com/Download/Detail.aspx?cguid=37300d99-41cf-65af-f29b-83ebcf06bd39&guid=69925f24-976f-2dfb-6a90-bd2968225de0
配置..自行配置吧,一样的.