自定义IHttpModule实现URL重写
HttpModule实现Url重写
比如,当接收到的用户请求的URL是UserInfo(\\d+).aspx这种形式时(这里采用了正则表达式,表示的是UserInfo(数字).asp这种URL)我们将会运行UserInfo.aspx?UserId=(\\d+)这样一个URL,这样网页就能正常显示了。
当然实现URL地址重写还需要借助一个类:HttpContext。HttpContext类中定义了RewritePath 方法,这个方法有四种重载形式,分别是:
RewritePath(String, Boolean) 使用给定路径和一个布尔值重写 URL,该布尔值用于指定是否修改服务器资源的虚拟路径。
RewritePath(String, String, String) 使用给定路径、路径信息和一个布尔值重写 URL,该布尔值用于指定是否修改服务器资源的虚拟路径。
RewritePath(String, String, String, Boolean) 使用给定虚拟路径、路径信息、查询字符串信息和一个布尔值重写 URL,该布尔值用于指定是否将客户端文件路径设置为重写路径。
对于这里四个重载方法的区别我不一一详细描述,因为在这里只用带一个参数的重载方法就能满足本文提出的要求。
我们的步骤如下:
首先编写自定义IHttpModule实现,这个定义只定义了两个方法Dispose()和Init()。在这里我们可以不用关注Dispose()这个方法,这个方法是用来实现如何最终完成资源的释放的。在Init方法中有一个HttpApplication参数,可以在方法中可以自定义对HttpApplication的事件处理方法。比如这里我们的代码如下:
///
///HttpModule 的摘要说明
///
public class HttpModule : IHttpModule
{
public HttpModule()
{
//
//TODO: 在此处添加构造函数逻辑
//
}
///
/// 实现接口的Init方法
///
///
public void Init(HttpApplication context)
{
//响应请求第一事件
context.BeginRequest += new EventHandler(ReUrl_BeginRequest);
//异常事件
context.Error += new EventHandler(Application_OnError);
}
///
/// 重写Url
///
/// 事件的源
/// 包含事件数据的 EventArgs
private void ReUrl_BeginRequest(object sender, EventArgs e)
{
//http信息
HttpContext context = ((HttpApplication)sender).Context;
//请求路径
string requestPath = context.Request.Path.ToLower();
//在此处进行URL处理、重写……如:
string url = requestPath.Replace("要替换的", "新的值");
//转到处理过的URL,(重写)
context.RewritePath(url);
}
public void Application_OnError(Object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
HttpContext context = application.Context;
//清除程序异常
context.Server.ClearError();
//异常时可重写向到指定的路径(如401、404页面)
HttpContext.Current.Response.Redirect("/");
return;
}
///
/// 实现接口的Dispose方法
///
public void Dispose()
{
//释放资源
}
}
------------------------------------------------------------------------------
PS:
首先写一个处理URLs重写的类,并且这个类必须继承IHttpHandler接口,以博客园的程序为例:
public class UrlReWriteModule : System.Web.IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest +=new EventHandler(context_BeginRequest);
}
public void Dispose()
{
}
}
UrlReWriteModule类就是处理URLs重写的类,继承IHttpHandler接口,实现该接口的两个方法,Init和Dispose。在Init方法里注册自己定义的方法,如上例所示:
content.BeginRequest +=new EventHandler(content_BeginRequest);
BeginRequest是一个事件,在收到新的Http请求时触发,content_BeginRequest就是触发时处理的方法。另外说明一点,HttpModules能注册的方法还有很多,如:EndRequest、Error、Disposed、PreSendRequestContent等等。
在content_BeginRequest方法中具体处理URLs重写的细节,比如,将 http://www.cnblogs.com/rrooyy/archive/2004/10/24/56041.html 重写为 http://www.cnblogs.com/archive.aspx?user=rrooyy&id=56041 (注:我没有仔细看DuDu的程序,这里只是举例而已)。然后将重新生成的Url用HttpContext.RewritePath()方法重写即可,如下:
private void context_BeginRequest(object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
// 获取旧的Url
string url = context.Request.Path.ToLower();
// 重新生成新的Url
string newUrl = ...; // 具体过程略
// 重写Url
context.RewritePath(newUrl);
}
提醒:newUrl的格式不是http://www.infotouch.com/user/archive.aspx,而是从当前应用程序根目录算起的绝对路径,如:user\archive.aspx,这一点请特别注意。
最后要web.config中注册重写URLs的类。
采用标签可以注册一个类;可以移除某个类,如果某个子目录不希望继承父目录的某个Http Module注册,就需要使用这个标签;可以移除所有的Http Module注册。
------------------------------------------------------------------------------
PS:项目实例
配置文件如下:
(IIS6)
<httpModules> <add name="urlRewriter" type="XXX.UrlRewriter.HttpModule,XXX.UrlRewriter" /> </httpModules>
注意:在IIS7中的节点为moudules
public class HttpModule : IHttpModule { #region IHttpModule 成员 public void Dispose() { } public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(context_BeginRequest); } void context_BeginRequest(object sender, EventArgs e) { HttpApplication app = (HttpApplication)sender; HttpContext context = app.Context; if (app == null || context == null) return; // URL定向 Rewriter.URLRewriter(app.Request.Url.AbsoluteUri, app); } #endregion }
public static void URLRewriter(string requestpath, HttpApplication app) { // 转换成小写 requestpath = requestpath.ToLower(); if (requestpath.IndexOf("http://") == -1) { requestpath = "http://" + requestpath; } List<UrlRules> urlRules = new UrlRules().UrlList("/config/SiteUrlReWriter.config"); foreach (UrlRules rule in urlRules) { string lookFor = "^" + rule.LookFor + "$"; lookFor = lookFor.ToLower(); Regex regex = new Regex(lookFor, RegexOptions.IgnoreCase); if (regex.IsMatch(requestpath)) { string sendTo = regex.Replace(requestpath, rule.SendTo); app.Context.RewritePath(ChangUrl(sendTo), true); break; } } }