2. 使用HttpModule来执行网址重写
创建一个
HttpModule很简单,只要创建一个实现
IHttpModule接口的类,该
IHttpModule接口定义了两个方法:
·
Init(HttpApplication),该方法在
HttpModule初始化时引发,通过该方法为
HttpApplication事件调用相应的事件委托;
·
Dispose(),当相应请求处理结束并发送回IIS调用此方法,通过此方法执行最终所有的清理和回收程序。
为了更加方便地为网址重写创建
HttpModule,从一开始我就创建一个抽象的基类(
BaseModuleRewriter),该类实现了
IHttpModule接口。在
Init(HttpApplication)事件中,它通过
BaseModuleRewriter_AuthorizeRequest方法引发了
HttpApplication的
AuthorizeRequest事件,该
BaseModuleRewriter_AuthorizeRequest方法通过该类的Rewrite()方法重写传入参数
HttpApplication对象的内部请求虚拟路径(
Path)。在
BaseModuleRewriter对象中,该
Rewrite()方法是抽象的,并且没有实际内容,但在继承自该类的对象中必须重载
Rewrite()方法并为该方法提供实际内容。
通过对该基类的继承,所有需要做的工作就是创建一个继承自
BaseModuleRewriter的类,重载
Rewrite()方法并在该方法中添加网址重写逻辑代码。下文列出
BaseModuleRewriter代码:

public abstract class BaseModuleRewriter : IHttpModule


{


public virtual void Init(HttpApplication app)

{

// WARNING! This does not work with Windows authentication!

// If you are using Windows authentication,

// change to app.BeginRequest

app.AuthorizeRequest += new EventHandler(this.BaseModuleRewriter_AuthorizeRequest);

}



public virtual void Dispose()

{}



protected virtual void BaseModuleRewriter_AuthorizeRequest(object sender, EventArgs e)

{

HttpApplication app = (HttpApplication) sender;

Rewrite(app.Request.Path, app);

}


protected abstract void Rewrite(string requestedPath, HttpApplication app);

}
注意:该
BaseModuleRewriter类将网址重写放在
AuthorizeRequest事件中调用,如果要使用Windows验证并使用文件验证模式时请修改代码将网址授权放在
BeginRequest或者
AuthenticateRequest事件中。
ModuleRewriter继承自
BaseModuleRewriter,并真正意义地实现了网址重写的操作,该类仅包含一个重载了的方法
Rewrite(),其内容如下文所示:

protected override void Rewrite(string requestedPath, System.Web.HttpApplication app)


{

// get the configuration rules

RewriterRuleCollection rules = RewriterConfiguration.GetConfig().Rules;

// iterate through each rule

for(int i = 0; i < rules.Count; i++)


{

// get the pattern to look for, and

// Resolve the Url (convert ~ into the appropriate directory)

string lookFor = "^" +

RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, rules[i].LookFor) + "$";

// Create a regex (note that IgnoreCase is set

)

Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);

// See if a match is found

if (re.IsMatch(requestedPath))


{

// match found - do any replacement needed

string sendToUrl = RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, re.Replace(requestedPath, rules[i].SendTo));

// Rewrite the URL

RewriterUtils.RewriteUrl(app.Context, sendToUrl);

break; // exit the for loop

}

}

}

该
Rewriter()方法以获取web.config文件中的网址重写规则的设置为起始,它通过循环访问各条网址重写规则,每次均获取当前规则中的
LookFor属性,用正则表达式验证并判断是否查找是否对当前请求的网址是否有匹配。
如果发现一条匹配,将用当前规则的SendTo值对请求的路径执行一个正则表达式替换,替换后的地址通过参数的形式传给
RewriterUtils.RewriteUrl()方法,
RewriterUtils是一个帮助类,它提供一对
HttpModule和
HttpHandler都可以使用的静态方法,
RewriterUrl()方法只是简单地调用了
HttpContext对象的
RewritePath()方法。
注意:你已经注意到了当执行正则表达式匹配和替换的时候调用了一个
RewriterUtils.ResolveUrl()方法。该帮助方法简单地替换了应用程序路径中“~”的所有实例。
我们已经探讨了主要的部分,但是还有其它一些组件诸如将web.config文件中XML格式化了的网址重写规则反序列化至一个对象的类定义、通过
HttpHandlerFactory实现网址重写的类定义等。本文最后三节将通过一些真实案例来探讨网址重写的技术。