实现 URL 重写

可以使用 ISAPI 筛选器在 IIS Web 服务器级别实现 URL 重写,也可以使用 HTTP 模块或 HTTP 处理程序在 ASP.NET 级别实现 URL 重写。本文重点介绍如何使用 ASP.NET 实现 URL 重写,因此我们将不对使用 ISAPI 筛选器实现 URL 重写的细节进行深入探讨。但是,有大量的第三方 ISAPI 筛选器可用于 URL 重写,例如:

ISAPI Rewrite

IIS Rewrite

PageXChanger

还有许多其他的筛选器!

通过 System.Web.HttpContext 类的 RewritePath() 方法,可以在 ASP.NET 级别实现 URL 重写。HttpContext 类包含有关特定 HTTP 请求的 HTTP 特定信息。对于 ASP.NET 引擎收到的每个请求,均为该请求创建一个 HttpContext 实例。此类具有如下属性:Request 和 Response,提供对传入请求和传出响应的访问;Application 和 Session,提供对应用程序和会话变量的访问;User,提供有关通过了身份验证的用户的信息;其他相关属性。

使用 Microsoft® .NET Framework Version 1.0,RewritePath() 方法可以接受单个字符串作为要使用的新路径。HttpContext 类的 RewritePath(string) 方法在内部对 Request 对象的 Path 属性和 QueryString 属性进行更新。除了 RewritePath(string),.NET Framework 1.1 还包括另一种形式的 RewritePath() 方法,此方法可以接受三个字符串输入参数。此备用重载形式不仅要设置 Request 对象的 Path 属性和 QueryString 属性,还要设置内部成员变量,这些变量用于计算 Request 对象的 PhysicalPath、PathInfo 和 FilePath 属性值。

要在 ASP.NET 中实现 URL 重写,需要创建 HTTP 模块或 HTTP 处理程序,以便完成以下操作:

检查被请求的路径,以确定 URL 是否需要重写。

如果需要重写,通过调用 RewritePath() 方法来重写路径。

例如,假设我们的网站中包含每个员工通过 /info/employee.aspx?empID=employeeID 均可访问的信息。为了使 URL 可以更多地被“删节”,我们可以决定通过以下地址来访问员工页面:/people/EmployeeName.aspx。这就是我们要使用 URL 重写的一个例子。也就是说,在请求 /people/ScottMitchell.aspx 页面时,我们要重写该 URL,以便使用 /info/employee.aspx?empID=1001 页面。

 使用 HTTP 模块执行 URL 重写

在 ASP.NET 级别执行 URL 重写时,可以使用 HTTP 模块或 HTTP 处理程序来执行重写。使用 HTTP 模块时,必须决定在请求有效期内的哪个时间点上来检查 URL 是否需要重写。乍一看,这似乎可以任意选择,但决定会以一种明显而微妙的方式对应用程序产生影响。由于内置 ASP.NET HTTP 模块使用 Request 对象的属性执行任务,因此选择在何处执行重写非常重要。(如上所述,重写路径将改变 Request 对象的属性值。)下面列出了这些密切相关的内置 HTTP 模块及其捆绑到的事件:



FormsAuthenticationModule



AuthenticateRequest



确定用户是否通过了窗体身份验证。如果没有,用户将被自动重定向到指定的登录页面。



FileAuthorizationMoudle



AuthorizeRequest



使用 Windows 身份验证时,此 HTTP 模块将检查以确保 Microsoft® Windows® 帐户对被请求的资源具有足够的权限。



UrlAuthorizationModule



AuthorizeRequest



检查以确保请求者可以访问指定的 URL。通过 Web.config 文件中的 <authorization> 和 <location> 元素来指定 URL 授权。


如上所述,BeginRequest 事件在 AuthenticateRequest 之前触发,后者在 AuthenticateRequest 之前触发。

可以执行 URL 重写的一个安全位置是在 BeginRequest 事件中。也就是说,如果 URL 需要重写,该操作将在任何一个内置 HTTP 模块运行后执行。使用窗体身份验证时,这种方法存在一定的缺陷。如果您以前使用过窗体身份验证,您会了解当用户访问受限资源时,他们将被自动重定向到指定的登录页面。成功登录后,用户将被返回到他们第一次尝试访问的页面。

如果在 BeginRequestAuthenticateRequest 事件中执行 URL 重写,登录页面(提交后)将把用户重定向到重写后的页面上。也就是说,假设用户在其浏览窗口中键入了 /people/ScottMitchell.aspx,此地址将被重写为 /info/employee.aspx?empID=1001。如果将 Web 应用程序配置为使用窗体身份验证,当用户第一次访问 /people/ScottMitchell.aspx 时,首先,URL 将被重写为 /info/employee.aspx?empID=1001;接下来,FormsAuthenticationModule 将运行,并将用户重定向到登录页面(如果需要)。但是,用户在成功登录后将被发送到 /info/employee.aspx?empID=1001,因为当 FormsAuthenticationModule 运行后,此 URL 即是请求的 URL。

同样,在 BeginRequestAuthenticateRequest 事件中执行重写时,UrlAuthorizationModule 看到的将是重写后的 URL。也就是说,如果您在 Web.config 文件中使用 <location> 元素来为特定的 URL 指定授权,则必须引用重写后的 URL。

要解决这些细微问题,您可以决定在 AuthorizeRequest 事件中执行 URL 重写。此方法解决了 URL 授权和窗体身份验证的一些问题,但同时也产生了新的问题:文件授权无法工作。使用 Windows 身份验证时,FileAuthorizationModule 将检查以确保通过身份验证的用户具有访问特定 ASP.NET 页面的相应权限。

假设一组用户对 C:\Inetput\wwwroot\info\employee.aspx 没有 Windows 级别的文件访问权限,并要尝试访问 /info/employee.aspx?empID=1001,他们将会收到授权错误消息。但是,如果我们将 URL 重写移到 AuthenticateRequest 事件中,当 FileAuthorizationModule 检查安全设置时,仍然认为被请求的文件是 people/ScottMitchell.aspx,因为该 URL 必须被重写。因此,文件授权检查将通过,允许此用户查看重写后的 URL /info/employee.aspx?empID=1001 的内容。

那么,应该何时在 HTTP 模块中执行 URL 重写?这取决于要使用的身份验证类型。如果不想使用任何身份验证,则无论 URL 重写发生在 BeginRequestAuthenticateRequest 还是 AuthorizeRequest 中都没有什么关系。如果要使用窗体身份验证而不使用 Windows 身份验证,请将 URL 重写放在 AuthorizeRequest 事件处理程序中执行。最后,如果要使用 Windows 身份验证,请在 BeginRequestAuthenticateRequest 事件进行过程中安排 URL 重写。

在 HTTP 处理程序中执行 URL 重写


也可以由 HTTP 处理程序或 HTTP 处理程序工厂执行 URL 重写。如上所述,HTTP 处理程序是负责生成特定类型请求的内容的类;HTTP 处理程序工厂是负责返回 HTTP 处理程序实例的类,该实例可以生成特定类型请求的内容。

在本文中,我们将对如何为 ASP.NET 网页创建 URL 重写 HTTP 处理程序工厂进行讨论。HTTP 处理程序工厂必须实现 IHttpHandlerFactory 接口,此接口包括 GetHandler() 方法。初始化相应的 HTTP 模块后,ASP.NET 引擎将确定为给定的请求调用哪个 HTTP 处理程序或 HTTP 处理程序工厂。如果要调用 HTTP 处理程序工厂,ASP.NET 引擎将为 Web 请求调用传入 HttpContext 的 HTTP 处理程序工厂的 GetHandler() 方法,以及一些其他信息。然后,HTTP 处理程序工厂必须返回一个对象,该对象将实现可以处理请求的 IHttpHandler

要通过 HTTP 程序程序执行 URL 重写,我们可以创建一个 HTTP 处理程序工厂,该处理程序工厂的 GetHandler() 方法将检查被请求的路径,以确定是否需要重写 URL。如果需要,它可以调用传入的 HttpContext 对象的 RewritePath() 方法,如前面所讨论的。最后,HTTP 处理程序工厂可以返回由 System.Web.UI.PageParser 类的 GetCompiledPageInstance() 方法返回的 HTTP 处理程序。(此技术与内置 ASP.NET 网页 HTTP 处理程序工厂 PageHandlerFactory 工作时所应用的技术相同。)

由于所有 HTTP 模块都将在实例化自定义 HTTP 处理程序工厂之前进行初始化,因此,在将 URL 重写放在事件的后半段时,使用 HTTP 处理程序工厂就会带来相同的风险,即文件授权无法工作。因此,如果您依赖于 Windows 身份验证和文件授权,您可能希望为 URL 重写使用 HTTP 模块方法。

在下一部分中,我们将对构建可重用的 URL 重写引擎进行讨论。在介绍了 URL 重写引擎(可通过下载本文的代码获得)之后,我们将在剩下的两个部分中对 URL 重写的实际使用情况进行介绍。首先,我们将讨论如何使用 URL 重写引擎,并介绍一个简单的 URL 重写示例。接下来,我们将利用重写引擎的正则表达式功能来提供真正“可删节”的 URL。