ASP.net的地址重写(URLRewriter)实现原理及代码示例 高露 一、概述 访问者输入:http://egojit.cnbolgs.com/default.aspx,实际请求和响应的地址却是:http://www.cnblogs.com/egojit/default.aspx, 这就是UrlRewrite,除了实现二级域名功能,它在简化用户输入地址、SEO、网站版本迭代更新等多个方面发挥着重要作用。 微软曾在.net framework 1.1中提供过一个名为URLRewriter的小工具供开发人员轻松实现UrlRewrite,下载地址为:http://download.microsoft.com/download/0/4/6/0463611e-a3f9-490d-a08c-877a83b797cf/MSDNURLRewriting.msi 本文以URLRewriter为例,在.net framework 2.0的环境下做了小部分优化调整,供大家学习和参考,能力有限,不足之处请大家及时指出。本文假设读者对URLRewriter、ASP.net的 Http管线有一定了解,否则请查阅相关资料。 二、配置 URLRewriter在web.config里通过自定义配置结合正则表达式来实现URL重写。 自定义节点的声明:
public class RewriterConfigSerializerSectionHandler : IConfigurationSectionHandler { ///
public object Create(object parent, object configContext, System.Xml.XmlNode section) { XmlSerializer ser = new XmlSerializer(typeof(RewriterConfiguration)); return ser.Deserialize(new XmlNodeReader(section)); } }//end class } 之前一直写WEB程序,很少用到自定义节点,直到一次写Windows Service用到了app.config,发现要读取自定义节点,就需要实现IConfigurationSectionHandler接口。 using System; using System.Web; using System.Web.Caching; using System.Configuration; using System.Xml.Serialization; namespace PaoTiao.PTRewriter.Config { [Serializable()] [XmlRoot("RewriterConfig")] public class RewriterConfiguration { private RewriterRuleCollection rules; ///
///
[Serializable()] public class RewriterRuleCollection : CollectionBase { ///
///RewriterRule对象 public virtual void Add(RewriterRule r) { this.InnerList.Add(r); } ///
public RewriterRule this[int index] { get { return (RewriterRule)this.InnerList[index]; } set { this.InnerList[index] = value; } } }//end class } using System; namespace PaoTiao.PTRewriter.Config { ///
[Serializable()] public class RewriterRule { private string mLookFor; private string mSendTo; ///
public string LookFor{ get { return this.mLookFor; } set { this.mLookFor = value; } } ///
public string SendTo{ get { return this.mSendTo; } set { this.mSendTo = value; } } }//end class }//end namespace 使用HttpModule实现地址重写 using System; using System.Web; namespace PaoTiao.PTRewriter { ///
public abstract class BaseModuleRewriter : IHttpModule { public virtual void Dispose() { } public virtual void Init(HttpApplication app) { app.BeginRequest += new EventHandler(this.BaseModuleRewriter_BeginRequest); } protected virtual void BaseModuleRewriter_BeginRequest(object sender, EventArgs e) { HttpApplication app = (HttpApplication)sender; Rewrite(app); } ///
///protected abstract void Rewrite(HttpApplication app); }//end class } 在Http模块中进行核心逻辑处理,源代码是在AuthorizeRequest事件中,此处我使用了BeginRequest事件。 对抽象方法Rewrite的实现。大家可以发现URL重写其实就一个核心方法:HttpContext.RewritePath 看看MSDN中对该方法的描述:指定内部重写路径,并允许请求的 URL 与资源的内部路径不同。 using System; using System.Text.RegularExpressions; using System.Configuration; using System.IO; namespace PaoTiao.PTRewriter { public class ModuleRewriter : BaseModuleRewriter { ///
///protected override void Rewrite(System.Web.HttpApplication app) { //开始跟踪日志 app.Context.Trace.Write("ModuleRewriter", "Entering ModuleRewriter"); //获取规则集合 Config.RewriterRuleCollection rules = Config.RewriterConfiguration.GetConfig().Rules; for (int i = 0; i < rules.Count; i++) { string lookFor = rules[i].LookFor; Regex reg = new Regex(lookFor, RegexOptions.IgnoreCase); if (reg.IsMatch(app.Request.Url.ToString())) { //获取目的URL string sendToUrl = reg.Replace(app.Request.Url.ToString(), rules[i].SendTo); //跟踪日志 app.Context.Trace.Write("ModuleRewriter", "Rewriting URL to " + sendToUrl); //地址重写 app.Context.RewritePath(sendToUrl); //Temp code for debug //using (StreamWriter sw = new StreamWriter(@"c:\test\rr.txt", true, System.Text.Encoding.UTF8)) //{ // sw.WriteLine(app.Request.Url.ToString()); // sw.WriteLine("--------------------------------------"); // sw.Close(); //} //退出for循环 break; } } //结束跟踪日志 app.Context.Trace.Write("ModuleRewriter", "Exiting ModuleRewriter"); } }//end class } 最后在web.config中注册自定义的Http模块: