- 浏览: 122023 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
zzl09:
哈哈 谢谢分享 想知道 博主用的什么UML工具呢?正相认真学 ...
初学UML之-------用例 -
kittychina:
http://www.cmswatch.com/是收费才能看的 ...
内容管理系统概述 -
kittychina:
很好!很好!
内容管理系统概述 -
464872333:
目前正在考虑这方面的,谢谢分享!
利用WebService实现远程数据库存取及不同站点间共享同一数据库
在 ASP.NET 中执行 URL 重写
发布日期: 8/23/2004 | 更新日期: 8/23/2004
Scott Mitchell
4GuysFromRolla.com
适用范围:
Microsoft® ASP.NET
摘要:介绍如何使用 Microsoft ASP.NET 执行动态 URL 重写。URL 重写是截取传入 Web 请求并自动将请求重定向到其他 URL 的过程。讨论实现 URL 重写的各种技术,并介绍执行 URL 重写的一些实际情况。
本页内容
引言 | |
URL 重写的常见用法 | |
请求到达 IIS 时将会发生什么情况 | |
实现 URL 重写 | |
构建 URL 重写引擎 | |
使用 URL 重写引擎执行简单的 URL 重写 | |
创建真正“可删节”的 URL | |
结论 | |
参考资料 |
引言
让我们花点时间来看一下网站上的一些 URL。您是否发现一些类似于 http://yoursite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&type=summary 的 URL?或者,您可能将一系列网页从一个目录或网站移动到另一个目录或网站,结果导致已将旧 URL 用作书签的访问者断开链接。在本文中,我们将了解如何通过将 http://yoursite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&type=summary 替换为类似于 http://yoursite.com/people/sales/chuck.smith 的网址,使用 URL 重写将那些冗长的 URL 缩写为富有意义且容易记忆的 URL。我们还将了解如何将 URL 重写用于创建智能 404 错误。
URL 重写是截取传入 Web 请求并自动将请求重定向到其他资源的过程。执行 URL 重写时,通常会检查被请求的 URL,并基于 URL 的值将请求重定向到其他 URL。例如,在进行网站重组而将 /people/ 目录下的所有网页移动到 /info/employees/ 目录中时,您可能希望使用 URL 重写来检查 Web 请求是否指向了 /people/ 目录中的文件。如果请求指向 /people/ 目录中的文件,您可能希望自动将请求重定向到 /info/employees/ 目录中的同一文件。
使用传统的 ASP,应用 URL 重写的唯一方法是编写 ISAPI 筛选器,或者购买提供 URL 重写功能的第三方产品。但是,使用 Microsoft® ASP.NET,您可以通过很多方法来轻松地创建您自己的 URL 重写软件。本文讨论了可供 ASP.NET 开发人员实现 URL 重写的各种技术,然后讨论了 URL 重写的一些实际使用情况。在深入讨论 URL 重写的技术细节之前,让我们先看一些可以使用 URL 重写的日常情景。
URL 重写的常见用法
创建数据驱动的 ASP.NET 网站时,通常会产生一个单个的网页,该网页基于查询字符串参数显示数据库数据的子集。例如,在设计电子商务站点时,您的任务之一便是允许用户浏览待售产品。为此,您可以创建一个名为 displayCategory.aspx 的页面,该页面将显示给定类别的产品。可以通过查询字符串参数来指定要查看的该类别的产品。也就是说,如果用户要浏览待售的 Widget 产品,并且所有 Widget 产品的 CategoryID 均为 5,则用户可以访问以下网址:http://yousite.com/displayCategory.aspx?CategoryID=5。
创建具有此类 URL 的网站有两点不足:首先,从最终用户的角度考虑,URL http://yousite.com/displayCategory.aspx?CategoryID=5 比较杂乱。可用性专家 Jakob Neilsen建议遵循以下标准来选择 URL:
• |
简短。 |
• |
易于键入。 |
• |
可以看出站点的结构。 |
• |
“可删节”,允许用户通过删除 URL 的组成部分来浏览站点。 |
我还要增加一条标准,即,URL 应该便于记忆。URL http://yousite.com/displayCategory.aspx?CategoryID=5 不符合 Neilsen 的任何标准,也不容易记住。要求用户键入查询字符串值将使 URL 的键入变得非常困难,并且只有了解查询字符串参数的用途及其名称/值对结构的富有经验的 Web 开发人员才能够对 URL 进行“删节”。
较好的方法是允许使用切合实际且容易记忆的 URL,如 http://yoursite.com/products/Widgets。只要看一眼 URL,您便可以推断出将要显示的内容 -- 有关 Widget 的信息。此 URL 也很容易记住和共享。我可以告诉我的同事“请查看 yoursite.com/products/Widgets,”,她可能无需再次问我 URL 是什么即可打开该页面。(尝试一下,您只需说出“Amazon.com 页面”即可!)此 URL 还将显示出来,并且应该是“可删节”的。也就是说,如果用户删去 URL 的末端,键入 http://yoursite.com/products,他们应该看到所有产品的列表,或者至少应该看到他们可以查看的所有类别的产品列表。
注意:要获得“可删节”URL 的最好示例,可考虑使用由许多 blog 引擎生成的 URL。要查看 2004 年 1 月 28 日的帖子,用户可以访问诸如 http://someblog.com/2004/01/28 的 URL。如果该 URL 被删节为 http://someblog.com/2004/01,用户将看到 2004 年 1 月的所有帖子。将该 URL 进一步删节为 http://someblog.com/2004 将显示 2004 年的所有帖子。
除了简化 URL 之外,URL 重写还经常用于处理网站重组,以免导致大量链接断开或书签过期。
请求到达 IIS 时将会发生什么情况
在正式研究 URL 如何实现重写之前,应首先了解 Microsoft® Internet Information Services (IIS) 如何处理传入请求,这一点非常重要。当请求到达 IIS Web 服务器时,IIS 检查被请求文件的扩展名以确定如何处理该请求。IIS 可以自行处理请求(如 HTML 页面、图像以及其他静态内容),或者将请求路由到 ISAPI 扩展。(ISAPI 扩展是一个处理传入 Web 请求的非托管编译类。其任务是生成被请求资源的内容。)
例如,当传入针对 Info.asp 网页的请求时,IIS 会将此消息路由到 asp.dll ISAPI 扩展。然后,该 ISAPI 扩展将加载被请求的 ASP 页面,执行该页面,并将所呈现的 HTML 返回给 IIS,然后,IIS 将该 HTML 发送回请求客户端。对于 ASP.NET 页面,IIS 会将此消息路由到 aspnet_isapi.dll ISAPI 扩展。然后,aspnet_isapi.dll ISAPI 扩展将处理操作传递给托管的 ASP.NET 辅助进程,该辅助程序将处理请求,并返回 ASP.NET 网页的呈现 HTML。
您可以自定义 IIS,以指定扩展名与 ISAPI 扩展的映射关系。图 1 显示了 Internet Information Services 管理工具的“应用程序配置”对话框。请注意,与 ASP.NET 有关的扩展名(.aspx、ascx、config、asmx、rem、cs、vb 及其他)均已映射到 aspnet_isapi.dll ISAPI 扩展。
图 1. 已配置的文件扩展名映射
讨论 IIS 如何管理传入请求稍稍超出了本文范围。但是可以在 Michele Leroux Bustamante 的文章 Inside IIS and ASP.NET 中找到对此内容的深入讨论。ASP.NET 引擎仅处理那些扩展名已明确映射至 IIS 中的 aspnet_isapi.dll 的传入 Web 请求,了解这一点非常重要。
使用 ISAPI 筛选器检查请求
IIS 除了可以将传入 Web 请求的文件扩展名映射到相应的 ISAPI 扩展之外,还将执行许多其他任务。例如,IIS 将尝试对发出请求的用户进行身份验证,并确定通过身份验证的用户是否有权限访问被请求的文件。在处理请求的有效期内,IIS 将经历几个状态。在每个状态下,IIS 都将引发可以使用 ISAPI 筛选器以编程方式进行处理的事件。
与 ISAPI 扩展一样,ISAPI 筛选器是在 Web 服务器上安装的非托管代码块。ISAPI 扩展被设计为可以响应针对特定文件类型的请求。另一方面,ISAPI 筛选器还包含可以对 IIS 引发的事件进行响应的代码。ISAPI 筛选器可以截取甚至修改传入和传出的数据。ISAPI 筛选器可以应用于很多方面,包括:
• |
身份验证和授权。 |
• |
记录和监视。 |
• |
HTTP 压缩。 |
• |
URL 重写。 |
虽然 ISAPI 筛选器可用于执行 URL 重写,但本文将讨论如何使用 ASP.NET 实现 URL 重写。不过,我们将对使用 ISAPI 筛选器与使用 ASP.NET 中的技术实现 URL 重写进行权衡。
请求进入 ASP.NET 引擎时将会发生什么情况
在 ASP.NET 之前,需要使用 ISAPI 筛选器来实现 IIS Web 服务器上的 URL 重写。由于 ASP.NET 引擎与 IIS 非常相似,因此可以使用 ASP.NET 进行 URL 重写。存在相似之处的原因在于 ASP.NET 引擎可以实现以下功能:
• |
在处理请求时可以引发事件。 |
• |
允许任意数量的 HTTP 模块处理所引发的事件,这与 IIS 的 ISAPI 筛选器相似。 |
• |
将呈现被请求资源这项任务委托给 HTTP 处理程序,该处理程序与 IIS 的 ISAPI 扩展相似。 |
与 IIS 一样,ASP.NET 引擎在请求的有效期内将会触发事件,通过发信号来表示其处理过程从一个状态改变为了另一个状态。例如,当 ASP.NET 引擎首次响应请求时,BeginRequest 事件将被触发。接下来触发的是 AuthenticateRequest 事件,该事件在已建立用户标识时出现。(此外,还有大量的其他事件:AuthorizeRequest、ResolveRequestCache 和 EndRequest,等等。这些事件属于 System.Web.HttpApplication 类;有关详细信息,请参阅位于以下网址的技术文档:HttpApplication Class Overview。)
正如上一部分所讨论的,可以创建 ISAPI 筛选器以响应 IIS 引发的事件。同样,ASP.NET 提供了 HTTP 模块,该模块可以响应由 ASP.NET 引擎引发的事件。可以将 ASP.NET Web 应用程序配置为具有多个 HTTP 模块。对于由 ASP.NET 引擎处理的每个请求,将初始化每个已配置的 HTTP 模块,并允许将事件处理程序绑定到处理请求期间所引发的事件。请注意,对每个请求均使用了许多内置 HTTP 模块。其中的一个内置 HTTP 模块是 FormsAuthenticationModule,该模块首先检查是否使用了窗体身份验证,如果使用,将检查是否对用户进行了身份验证。如果没有使用,会自动将用户重定向到指定的登录页面。
如上所述,通过使用 IIS,传入请求将最终发送给 ISAPI 扩展,而 ISAPI 扩展的任务是返回特定请求的数据。例如,在请求传统的 ASP 网页时,IIS 将请求传递给 asp.dll ISAPI 扩展,该扩展的任务是返回被请求的 ASP 页面的 HTML 标记。ASP.NET 引擎使用相似的方法。初始化 HTTP 模块后,ASP.NET 引擎的下一项任务是确定应由哪个 HTTP 处理程序来处理请求。
所有通过 ASP.NET 引擎传递的请求最终都将到达 HTTP 处理程序或 HTTP 处理程序工厂(HTTP 处理程序工厂仅返回 HTTP 处理程序的实例,然后使用该实例来处理请求)。最终的 HTTP 处理程序将返回响应,即呈现被请求的资源。此响应将被发送回 IIS,然后 IIS 将响应返回给提出请求的用户。
ASP.NET 包括许多内置的 HTTP 处理程序。例如,PageHandlerFactory 用于呈现 ASP.NET 网页。WebServiceHandlerFactory 用于呈现 ASP.NET Web 服务的响应 SOAP 信封。TraceHandler 将向 trace.axd 呈现请求的 HTML 标记。
图 2 描述了如何处理对 ASP.NET 资源的请求。首先,IIS 接收到请求,并将请求调度给 aspnet_isapi.dll。接下来,ASP.NET 引擎对已配置的 HTTP 模块进行初始化。最后将调用正确的 HTTP 处理程序,并呈现被请求的资源,将所生成的标记返回给 IIS 和请求客户端。
图 2. IIS 和 ASP.NET 正在处理请求
创建和注册自定义 HTTP 模块和 HTTP 处理程序
创建自定义 HTTP 模块和 HTTP 处理程序是相对简单的任务,包括创建实现正确接口的托管类。HTTP 模块必须实现 System.Web.IHttpModule 接口,而 HTTP 处理程序和 HTTP 处理程序工厂必须分别实现 System.Web.IHttpHandler 接口和 System.Web.IHttpHandlerFactory 接口。创建 HTTP 处理程序和 HTTP 模块的细节超出了本文的范围。要获得详细的背景知识,请阅读 Mansoor Ahmed Siddiqui 的文章 HTTP Handlers and HTTP Modules in ASP.NET。
创建了自定义 HTTP 模块或 HTTP 处理程序之后,必须将其注册到 Web 应用程序。为整个 Web 服务器注册 HTTP 模块和 HTTP 处理程序仅需在 machine.config 文件中进行简单的添加即可;而为特定 Web 应用程序注册 HTTP 模块或 HTTP 处理程序包括向应用程序的 Web.config 文件中添加几行 XML。
特别要说明的是,要将 HTTP 模块添加到 Web 应用程序,应在 Web.config 的 configuration/system.web 部分添加以下几行:
<httpModules> <add type="type" name="name" /></httpModules>
type 值提供了 HTTP 模块的程序集和类名称,而 name 值提供了友好名称,可以在 Global.asax 文件中使用此友好名称来引用 HTTP 模块。
Web.config 的 configuration/system.web 部分中的 <httpHandlers> 标记对 HTTP 处理程序和 HTTP 处理程序工厂进行了配置,如下所示:
<httpHandlers> <add verb="verb" path="path" type="type" /></httpHandlers>
如上所述,对于每个传入请求,ASP.NET 引擎将确定应使用哪个 HTTP 处理程序来呈现请求。此决定是基于传入请求的动词和路径做出的。动词将指定所作出的 HTTP 请求的类型(GET 或 POST),而路径将指定被请求文件的位置和文件名。因此,如果我们希望 HTTP 处理程序处理对扩展名为 .scott 的文件的所有请求(GET 或 POST),可以在 Web.config 文件中添加下面几行:
<httpHandlers> <add verb="*" path="*.scott" type="type" /></httpHandlers>
其中,type 是 HTTP 处理程序的类型。
注意:注册 HTTP 处理程序时,应确保 HTTP 处理程序使用的扩展名已从 IIS 映射到 ASP.NET 引擎,这一点非常重要。也就是说,在本 .scott 示例中,如果 .scott 扩展名没有从 IIS 映射到 aspnet_isapi.dll ISAPI 扩展,则对文件 foo.scott 的请求将导致 IIS 试图返回文件 foo.scott 的内容。为了使 HTTP 处理程序可以处理此请求,必须将 .scott 扩展名映射到 ASP.NET 引擎。然后,ASP.NET 引擎将把请求正确地路由到相应的 HTTP 处理程序。
有关注册 HTTP 模块和 HTTP 处理程序的详细信息,请务必参考 <httpModules> element documentation 和 <httpHandlers> element documentation。
实现 URL 重写
可以使用 ISAPI 筛选器在 IIS Web 服务器级别实现 URL 重写,也可以使用 HTTP 模块或 HTTP 处理程序在 ASP.NET 级别实现 URL 重写。本文重点介绍如何使用 ASP.NET 实现 URL 重写,因此我们将不对使用 ISAPI 筛选器实现 URL 重写的细节进行深入探讨。但是,有大量的第三方 ISAPI 筛选器可用于 URL 重写,例如:
• | |
• | |
• | |
• |
还有许多其他的筛选器! |
通过 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 处理程序,以便完成以下操作:
1. |
检查被请求的路径,以确定 URL 是否需要重写。 |
2. |
如果需要重写,通过调用 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 模块及其捆绑到的事件:
HTTP 模块 | 事件 | 说明 |
FormsAuthenticationModule |
AuthenticateRequest |
确定用户是否通过了窗体身份验证。如果没有,用户将被自动重定向到指定的登录页面。 |
FileAuthorizationMoudle |
AuthorizeRequest |
使用 Windows 身份验证时,此 HTTP 模块将检查以确保 Microsoft® Windows® 帐户对被请求的资源具有足够的权限。 |
UrlAuthorizationModule |
AuthorizeRequest |
检查以确保请求者可以访问指定的 URL。通过 Web.config 文件中的 <authorization> 和 <location> 元素来指定 URL 授权。 |
如上所述,BeginRequest 事件在 AuthenticateRequest 之前触发,后者在 AuthenticateRequest 之前触发。
可以执行 URL 重写的一个安全位置是在 BeginRequest 事件中。也就是说,如果 URL 需要重写,该操作将在任何一个内置 HTTP 模块运行后执行。使用窗体身份验证时,这种方法存在一定的缺陷。如果您以前使用过窗体身份验证,您会了解当用户访问受限资源时,他们将被自动重定向到指定的登录页面。成功登录后,用户将被返回到他们第一次尝试访问的页面。
如果在 BeginRequest 或 AuthenticateRequest 事件中执行 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。
同样,在 BeginRequest 或 AuthenticateRequest 事件中执行重写时,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 重写发生在 BeginRequest、AuthenticateRequest 还是 AuthorizeRequest 中都没有什么关系。如果要使用窗体身份验证而不使用 Windows 身份验证,请将 URL 重写放在 AuthorizeRequest 事件处理程序中执行。最后,如果要使用 Windows 身份验证,请在 BeginRequest 或 AuthenticateRequest 事件进行过程中安排 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。
构建 URL 重写引擎
为了有助于描述如何在 ASP.NET Web 应用程序中实现 URL 重写,我创建了 URL 重写引擎。此重写引擎将提供以下功能:
• |
使用 URL 重写引擎的 ASP.NET 页面开发人员可以在 Web.config 文件中指定重写规则。 |
• |
重写规则可以使用正则表达式来实现功能强大的重写规则。 |
• |
可以轻松地将 URL 重写配置为使用 HTTP 模块或 HTTP 处理程序。 |
在本文中,我们将介绍仅使用 HTTP 模块的 URL 重写。要查看如何使用 HTTP 处理程序来执行 URL 重写,请参考可随本文下载的代码。
为 URL 重写引擎指定配置信息
让我们先介绍一下 Web.config 文件中重写规则的结构。首先,您需要在 Web.config 文件中指明要使用 HTTP 模块还是 HTTP 处理程序来执行 URL 重写。在下载代码中,Web.config 文件包含两个已注释掉的条目:
<!--<httpModules> <add type="URLRewriter.ModuleRewriter, URLRewriter" name="ModuleRewriter" /></httpModules>--><!--<httpHandlers> <add verb="*" path="*.aspx" type="URLRewriter.RewriterFactoryHandler, URLRewriter" /></httpHandlers>-->
注释掉 <httpModules> 条目,以使用 HTTP 模块执行重写;注释掉 <httpHandlers> 条目,以使用 HTTP 处理程序执行重写。
除了指定使用 HTTP 模块还是 HTTP 处理程序执行重写外,Web.config 文件还包含重写规则:重写规则由两个字符串组成:要在被请求的 URL 中查找的模式;要替换此模式的字符串(如果找到)。在 Web.config 文件中,此信息是使用以下语法表达的:
<RewriterConfig> <Rules> <RewriterRule> <LookFor>要查找的模式</LookFor> <SendTo>要用来替换模式的字符串</SendTo> </RewriterRule> <RewriterRule> <LookFor>要查找的模式</LookFor> <SendTo>要用来替换模式的字符串</SendTo> </RewriterRule> ... </Rules></RewriterConfig>
每个重写规则均由 <RewriterRule> 元素表达。要搜索的模式由 <LookFor> 元素指定,而要替换所找到的模式的字符串将在 <SentTo> 元素中输入。这些重写规则将从头到尾进行计算。如果发现与某个规则匹配,URL 将被重写,并且对重写规则的搜索将会终止。
在 <LookFor> 元素中指定模式时,请注意,要使用正则表达式来执行匹配和字符串替换。(稍后,我们将介绍一个真实的示例,说明如何使用正则表达式来搜索模式。)由于模式是正则表达式,应确保转义正则表达式中的任何保留字符。(一些正则表达式保留字符包括:.、?、^、$ 及其他。可以通过在前面加反斜杠(如 \.)对这些字符进行转义,以匹配文字句点。)
使用 HTTP 模块执行 URL 重写
创建 HTTP 模块与创建可以实现 IHttpModule 接口的类一样简单。IHttpModule 接口定义了两种方法:
• |
Init(HttpApplication)。此方法在初始化 HTTP 模块后触发。在此方法中,您将把事件处理程序绑定到相应的 HttpApplication 事件。 |
• |
Dispose()。当请求已完成并已发送回 IIS 时调用此方法。您应当在此处执行所有最终的清除操作。 |
为了便于为 URL 重写创建 HTTP 模块,我将从创建抽象基类 BaseModuleRewriter 开始介绍。此类将实现 IHttpModule。在 Init() 事件中,它将 HttpApplication 的 AuthorizeRequest 事件绑定到 BaseModuleRewriter_AuthorizeRequest 方法。BaseModuleRewriter_AuthorizeRequest 方法将调用该类传入被请求的 Path 的 Rewrite() 方法,以及传入 Init() 方法的 HttpApplication 对象。Rewrite() 方法是抽象的,也就是说,在 BaseModuleRewriter 类中,Rewrite() 方法没有方法主体;从 BaseModuleRewriter 派生而来的类必须覆盖此方法并提供方法主体。
具有此基类后,只需创建由 BaseModuleRewriter 派生的类即可,该类可以覆盖 Rewrite() 并在那里执行 URL 重写逻辑。下面显示了 BaseModuleRewriter 的代码。
public abstract class BaseModuleRewriter : IHttpModule{ public virtual void Init(HttpApplication app) { // 警告!此代码不适用于 Windows 身份验证! // 如果使用 Windows 身份验证, // 请改为 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 事件中执行 URL 重写。如上所述,如果将 Windows 身份验证与文件授权结合使用,您需要对此做出更改,以便可以在 BeginRequest 或 AuthenticateRequest 事件中执行 URL 重写。
ModuleRewriter 类扩展了 BaseModuleRewriter 类,并负责执行实际的 URL 重写。ModuleRewriter 包含单一覆盖方法(Rewrite()),如下所示:
protected override void Rewrite(string requestedPath, System.Web.HttpApplication app){ // 获得配置规则 RewriterRuleCollection rules = RewriterConfiguration.GetConfig().Rules; // 遍历每个规则... for(int i = 0; i < rules.Count; i++) { // 获得要查找的模式,并且 // 解析 Url(转换为相应的目录) string lookFor = "^" + RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, rules[i].LookFor) + "___FCKpd___6quot;; // 创建 regex(请注意,已设置 IgnoreCase...) Regex re = new Regex(lookFor, RegexOptions.IgnoreCase); // 查看是否找到了匹配的规则 if (re.IsMatch(requestedPath)) { // 找到了匹配的规则 -- 进行必要的替换 string sendToUrl = RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, re.Replace(requestedPath, rules[i].SendTo)); // 重写 URL RewriterUtils.RewriteUrl(app.Context, sendToUrl); break; // 退出 For 循环 } }}
Rewrite() 方法从获取 Web.config 文件中的一组重写规则开始。然后,它将遍历重写规则,每次遍历一个,对于每个规则,它将获取规则的 LookFor 属性,并使用正则表达式来确定是否在被请求的 URL 中找到了匹配的规则。
如果找到了匹配的规则,将在具有 SendTo 属性值的被请求路径上执行正则表达式替换。然后,替换后的 URL 将被传递到 RewriterUtils.RewriteUrl() 方法中。RewriterUtils 是一个 helper 类,此类将提供一对由 URL 重写 HTTP 模块和 HTTP 处理程序使用的静态方法。RewriterUrl() 方法仅调用 HttpContext 对象的 RewriteUrl() 方法。
注意:您可能已注意到,执行正则表达式匹配和替换时,将调用 RewriterUtils.ResolveUrl()。此 helper 方法只替换具有应用程序路径值的字符串中的所有 ~ 实例。
URL 重写引擎的整个代码可随本文下载。我们已经介绍了大部分密切相关的组件,但还有一些其他组件(例如,对 Web.config 文件中 XML 格式的重写规则进行反序列化以使其成为对象的类),以及用于 URL 重写的 HTTP 处理程序工厂。本文剩余的三个部分将对 URL 重写的实际使用情况进行介绍。
使用 URL 重写引擎执行简单的 URL 重写
为了实际演示 URL 重写引擎,我们来构建一个使用简单 URL 重写的 ASP.NET Web 应用程序。假设我们所工作的公司通过网络销售分类产品。这些产品分为以下几个类别:
类别 ID | 类别名称 |
1 |
饮料 |
2 |
调味品 |
3 |
糖果 |
4 |
奶制品 |
... |
... |
假设我们已创建了名为 ListProductsByCategory.aspx 的 ASP.NET 网页,该网页在查询字符串中接受类别 ID 值,并显示属于该类的所有产品。因此,要查看我们销售的饮料的用户可以访问 ListProductsByCategory.aspx?CategoryID=1,而那些要查看奶制品的用户可以访问 ListProductsByCategory.aspx?CategoryID=4。此外,还假设我们有一个名为 ListCategories.aspx 的页面,该页面列出了待售的所有产品类别。
很显然,这是一个 URL 重写事例,因为提供给用户的 URL 没有为用户带来任何意义,也没有为他们提供任何“可删节性”。因此,让我们使用 URL 重写,以便在用户访问 /Products/Beverages.aspx 时,他们的 URL 将被重写为 ListProductsByCategory.aspx?CategoryID=1。我们可以在 Web.config 文件中使用以下 URL 重写规则来实现此功能。
<RewriterConfig> <Rules> <!-- 产品制表者规则 --> <RewriterRule> <LookFor>~/Products/Beverages\.aspx</LookFor> <SendTo>~/ListProductsByCategory.aspx?CategoryID=1</SendTo> </RewriterRule> <RewriterRule> </Rules></RewriterConfig>
正如您可以看到的,此规则将进行搜索,以查看用户请求的路径是否为 /Products/Beverages.aspx。如果是,它便将 URL 重写为 /ListProductsByCategory.aspx?CategoryID=1。
注意:请注意,<LookFor> 元素对 Beverages.aspx 中的句点进行了转义。这是因为在正则表达式模式中使用了 <LookFor> 值,并且句点是正则表达式中的特殊字符,该字符表示“匹配任意字符”,例如,与 URL /Products/BeveragesQaspx 匹配。通过转义句点(使用 \.),可以表明我们要匹配的是文字句点,而不是任何旧的字符。
有了此规则之后,当用户访问 /Products/Beverages.aspx 时,页面上将显示待售的饮料。图 3 显示了访问 /Products/Beverages.aspx 的浏览器的快照。请注意,在浏览器的地址栏中,URL 将读取 /Products/Beverages.aspx,但用户实际看到的是 ListProductsByCategory.aspx?CategoryID=1 的内容。(实际上,Web 服务器上根本不存在 /Products/Beverages.aspx 文件!)
图 3. 重写 URL 之后请求类别
与 /Products/Beverages.aspx 相似,下面我们要为其他产品类别添加重写规则。此操作仅包括在 Web.config 文件的 <Rules> 元素内添加附加的 <RewriterRule> 元素。请参阅下载内容中的 Web.config 文件,以获取用于此演示的一组完整的重写规则。
为了使 URL 更具可删节性,最好使用户只需从 /Products/Beverages.aspx 中删除 Beverages.aspx 即可看到产品类别的列表。乍一看,这可能是一项很普通的任务(只需添加一个将 /Products/ 映射到 /ListCategories.aspx 的重写规则即可)。但此操作存在一个微妙之处,即您必须首先创建一个 /Products/ 目录,并在 /Products/ 目录中添加一个空的 Default.aspx 文件。
要理解需要执行这些额外步骤的原因,可以参考前面的内容,即 URL 重写引擎位于 ASP.NET 级别上。也就是说,如果 ASP.NET 引擎永远没有机会处理请求,URL 重写引擎就没有办法检测传入的 URL。而且,请记住,仅当被请求的文件具有相应的扩展名时,IIS 才会将传入请求传递给 ASP.NET 引擎。因此,如果用户访问 /Products/,而 IIS 没有看到任何文件扩展名,那么它将检查目录,以查看是否存在这样一个文件,即该文件名为默认文件名中的一个。(Default.aspx、Default.htm、Default.asp 等等。“IIS 管理”对话框中“Web 服务器属性”对话框的“文档”选项卡对这些默认文件名进行了定义。)当然,如果 /Products/ 目录不存在,IIS 将返回 HTTP 404 错误。
因此,我们需要创建 /Products/ 目录。另外,我们还需要在此目录中创建一个文件 Default.aspx。这样,当用户访问 /Products/ 时,IIS 将检测目录,查看是否存在一个名为 Default.aspx 的文件,然后将处理过程传递给 ASP.NET 引擎。然后,URL 重写器将在重写 URL 时分解。
创建目录和 Default.aspx 文件后,请继续操作,并向 <Rules> 元素中添加以下重写规则:
<RewriterRule> <LookFor>~/Products/Default\.aspx</LookFor> <SendTo>~/ListCategories.aspx</SendTo></RewriterRule>
有了此规则之后,当用户访问 /Products/ 或 /Products/Default.aspx 时,他们将看到产品类别列表,如图 4 所示。
图 4. 向 URL 添加“可删节性”
处理回发
如果要重写的 URL 中包含一个服务器端的 Web 窗体并执行回发,则窗体回发后,将使用带下划线的 URL。也就是说,如果用户在浏览器中输入 /Products/Beverages.aspx,他们在浏览器地址栏中看到的将是 /Products/Beverages.aspx,但是他们看到的内容将是 ListProductsByCategory.aspx?CategoryID=1 的内容。如果 ListProductsByCategory.aspx 执行了回发,用户将被回发到 ListProductsByCategory.aspx?CategoryID=1,而不是 /Products/Beverages.aspx。这样不会中断任何内容,但从用户的角度考虑,如果单击按钮时突然看到 URL 更改会使他们感到不安。
出现这种情况的原因是:在呈现 Web 窗体时,它会将其操作属性直接设置为 Request 对象中文件路径的值。当然,在呈现 Web 窗体时,URL 已从 /Products/Beverages.aspx 重写为 ListProductsByCategory.aspx?CategoryID=1,这表明 Request 对象报告用户要访问 ListProductsByCategory.aspx?CategoryID=1。只需使服务器端窗体不呈现操作属性即可解决此问题。(默认情况下,如果窗体不包含操作属性,浏览器将会回发。)
不幸的是,Web 窗体不允许您明确指定操作属性,也不允许您设置某些属性以禁用操作属性的呈现。因此,我们必须自己来扩展 System.Web.HtmlControls.HtmlForm 类,覆盖 RenderAttribute() 方法并明确指出它不会呈现操作属性。
由于继承功能,我们可以获得 HtmlForm 类的所有功能,并且只需添加几行代码即可获得所需的行为。以下显示了自定义类的完整代码:
namespace ActionlessForm { public class Form : System.Web.UI.HtmlControls.HtmlForm { protected override void RenderAttributes(HtmlTextWriter writer) { writer.WriteAttribute("name", this.Name); base.Attributes.Remove("name"); writer.WriteAttribute("method", this.Method); base.Attributes.Remove("method"); this.Attributes.Render(writer); base.Attributes.Remove("action"); if (base.ID != null) writer.WriteAttribute("id", base.ClientID); } }}
已被覆盖的 RenderAttributes() 方法的代码仅包含 HtmlForm 类的 RenderAttributes() 方法的准确代码,而不设置操作属性。(我使用 Lutz Roeder 的 Reflector 来查看 HtmlForm 类的源代码。)
创建此类并对其进行编译之后,要在 ASP.NET Web 应用程序中使用它,应首先将其添加到 Web 应用程序的 References 文件夹中。然后,要使用它来代替 HtmlForm 类,只需在 ASP.NET 网页的顶部添加以下内容即可:
<%@ Register TagPrefix="skm" Namespace="ActionlessForm" Assembly="ActionlessForm" %>
然后,将 <form runat="server">(如果有)替换为:
<skm:Form id="Form1" method="post" runat="server">
并将右边的 </form> 标记替换为:
</skm:Form>
您可以在 ListProductsByCategory.aspx(包含在本文的下载代码中)中发现操作中的此自定义 Web Form 类。下载内容中还包含了用于无操作 Web Form 的 Visual Studio .NET 项目。
注意:如果要重写的目标 URL 没有执行回发,则无需使用此自定义 Web Form 类。
创建真正“可删节”的 URL
前一部分中介绍的简单 URL 重写显示了如何轻松地为 URL 重写引擎配置新的重写规则。但在使用正则表达式时,重写规则的真正功能才会发挥更大作用,本部分将对此进行探讨。
Blog 在当今正变得越来越流行,似乎每个人都拥有自己的 blog。如果您不熟悉 blog:blog 是经常更新的个人页面,通常作为联机期刊。大多数 blog 只记录每天发生的事情,还有一些 blog 可能关注于特定的主题(例如,电影回顾、体育团队或计算机技术)。
可以在任何地点对 blog 进行更新,更新频率为从每天几次到每周一次或两次,具体情况取决于作者。通常,blog 主页将显示最近的 10 个条目,但实际上,所有 blog 软件均提供存档,访问者可以通过存档读取较早的帖子。Blog 是用于“可删节”URL 的一个功能强大的应用程序。假设在搜索 blog 的存档时,您在 URL /2004/02/14.aspx 上发现了您自己。如果您发现自己在阅读 2004 年 2 月 14 日的帖子,您是否觉得很惊讶?而且,您可能希望查看 2004 年 2 月的所有帖子,在这种情况下,您可以尝试将 URL 删节为 /2004/02/。要查看 2004 年的所有帖子,您可以尝试访问 /2004/。
维护 blog 时,最好为访问者提供此级别的 URL“可删节性”。许多 blog 引擎都提供此功能,但我们将讨论如何使用 URL 重写来实现此功能。
首先,我们需要一个 ASP.NET 网页,此页面将按照日、月或年来显示 blog 条目。假设我们有一个 ShowBlogContent.aspx 页面,该页面的查询字符串参数为年、月和日。要查看 2004 年 2 月 14 日的帖子,我们可以访问 ShowBlogContent.aspx?year=2004&month=2&day=14。要查看 2004 年 2 月的所有帖子,我们可以访问 ShowBlogContent.aspx?year=2004&month=2。最后,要查看 2004 年的所有帖子,我们可以浏览到 ShowBlogContent.aspx?year=2004。(可以在本文的下载内容中找到 ShowBlogContent.aspx 的代码。)
在这种情况下,如果用户访问 /2004/02/14.aspx,我们需要将 URL 重写为 ShowBlogContent.aspx?year=2004&month=2&day=14。所有三种情况(URL 指定了年、月和日时;URL 仅指定了年和月时;URL 仅指定了年时)均可使用重写规则进行处理:
<RewriterConfig> <Rules> <!-- Blog 内容显示程序规则 --> <RewriterRule> <LookFor>~/(\d{4})/(\d{2})/(\d{2})\.aspx</LookFor> <SendTo>~/ShowBlogContent.aspx?year=$1&month=$2&day=$3</SendTo> </RewriterRule> <RewriterRule> <LookFor>~/(\d{4})/(\d{2})/Default\.aspx</LookFor> <SendTo><![CDATA[~/ShowBlogContent.aspx?year=$1&month=$2]]></SendTo> </RewriterRule> <RewriterRule> <LookFor>~/(\d{4})/Default\.aspx</LookFor> <SendTo>~/ShowBlogContent.aspx?year=$1</SendTo> </RewriterRule> </Rules></RewriterConfig>
这些重写规则表明了正则表达式的功能。在第一个规则中,我们使用模式 (\d{4})/(\d{2})/(\d{2})\.aspx 查找 URL。在简明英语中,它对应了这样一个字符串:首先是四个数字,后跟一个斜杠,然后是两个数字,后跟一个斜杠,然后再跟两个数字,最后是一个 .aspx。每个数字组周围的括号非常重要,通过它可以在相应的 <SendTo> 属性中引用这些括号内的匹配字符。 特别是,我们可以针对第一、第二和第三个括号组分别使用 $1、$2 和 $3 引用回括号内的匹配组。
注意:由于 Web.config 文件采用 XML 格式,但是必须对元素文字部分中的字符(如 &、< 和 >)进行转义。在第一个规则的 <SendTo> 元素中,& 被转义为 &。在第二个规则的 <SendTo> 中使用了另外一种技术(使用 <![CDATA[...]]> 元素),无需对内部的内容进行转义。可以使用两种方法中的任何一种,并且都会得到相同的结果。
图 5、6 和 7 显示了操作中的 URL 重写。数据实际上是从我的 blog http://scottonwriting.net/ 中拖过来的。图 5 中显示了 2003 年 11 月 7 日的帖子;图 6 中显示了 2003 年 11 月的所有帖子;图 7 显示了 2003 年的所有帖子。
图 5. 2003 年 11 月 7 日的帖子
图 6. 2003 年 11 月的所有帖子
<str
相关推荐
ASP.NET 中执行 URL 重写实例教程
下面将详细探讨URL重写的概念、原因、实现方法以及在ASP.NET中的应用。 1. **URL重写概念**: URL重写是Web应用程序的一种技术,它允许服务器根据预定义的规则将请求的URL转换为另一个URL。这种转换在后台发生,...
URL 重写技术在 ASP.NET 中主要通过 `HttpModule` 和 `UrlRoutingModule` 类实现。下面将详细介绍 ASP.NET 2.0 的 URL 重写机制及其应用。 1. **URL 重写原理**: URL 重写是服务器端的一种技术,当用户请求一个...
在ASP.NET中,实现URL重写主要依赖于`System.Web.Routing`命名空间中的`Route`类。下面将详细介绍如何使用`Route`类进行URL重写,以及相关的源码实例。 1. **安装和配置** 首先,确保你的项目引用了`System.Web....
在URL重写中,C#代码用于定义重写规则,这些规则告诉系统何时以及如何执行重写。例如,你可以创建一个路由规则,当用户访问`/Product/{category}/{id}`时,路由引擎会自动解析`category`和`id`参数,并调用相应的...
以下将详细介绍四种在ASP.NET中实现URL重写的方法。 ### 方法一:Web.config配置 在ASP.NET中,最常用且基础的URL重写方式是通过修改`Web.config`文件来实现。在`<system.webServer>`节点下添加`<rewrite>`节点,...
在ASP.NET中,URL重写是指在内部处理请求时,将用户输入的原始URL转换为不同的内部处理URL。这主要通过IIS服务器模块或ASP.NET应用程序中的HTTP模块来实现。URL重写的核心在于创建一个规则集,这些规则定义了如何将...
在本文中,我们将深入探讨ASP.NET URL重写的核心概念、工作原理以及如何配置和使用。 **1. URL重写的基本概念** URL重写是一种技术,它允许服务器在接收到客户端请求时改变请求的目标URL,而不会影响客户端浏览器...
在ASP.NET MVC框架中,URL重写和优化能够使应用程序的网址更加美观、可读,同时还能帮助隐藏技术细节,提高网站的SEO(搜索引擎优化)效果。 **URL重写** 1. **原理**:URL重写是指在服务器端将用户请求的实际URL...
在ASP.NET中,实现URL重写通常包括以下步骤: 1. 引入`System.Web.Routing`命名空间。 2. 在全局.asax文件(Global.asax.cs)的`Application_Start`方法中注册路由规则。 3. 定义路由规则,包括模板、处理程序和可能...
在这个“asp.net url重写 demo”项目中,我们看到使用了Intelligencia.UrlRewriter.dll组件来实现这一功能,这是一个广泛使用的开源URL重写库,适用于.NET Framework 3.5。 首先,让我们了解URL重写的基本原理。URL...
在提供的压缩包文件"UrlRewrite"中,可能包含了ASP.NET URL重写的配置示例或者相关的代码实现,可以帮助你更好地理解和应用这些技术。学习并熟练掌握这些知识,对于提升ASP.NET应用的性能和SEO优化有着极大的帮助。...
用ASP.NET实现URL重写 用ASP.NET实现URL重写 用ASP.NET实现URL重写 用ASP.NET实现URL重写 用ASP.NET实现URL重写 用ASP.NET实现URL重写 用ASP.NET实现URL重写 用ASP.NET实现URL重写
1. **配置问题**:在 ASP.NET 1.1 中,需要在 Web.config 文件中配置 HttpModule。如果配置不正确,可能导致应用程序无法启动或重写规则不起作用。确保正确添加 `<httpModules>` 和相应的 `<add>` 元素,指定模块的...
在ASP.NET框架中,URL重写通过修改HTTP请求的URL来实现,使得应用程序可以处理不同的URL,而实际执行的逻辑保持不变。 URLRewriter是ASP.NET中一个常用的URL重写库,它是由IIS(Internet Information Services)的...
在ASP.NET开发中,URL重写和页面静态化是两种重要的技术,它们对提升网站性能、优化搜索引擎排名以及保持良好的用户体验具有显著作用。下面将详细解释这两种技术,并结合HttpModuleDemo示例进行深入探讨。 一、URL...
在ASP.NET中,有多种实现URL重写的方法。IIS Web服务器层面可以通过ISAPI过滤器实现,但本文重点在于ASP.NET级别的解决方案,主要使用HttpModule和HttpHandler。HttpModule在ASP.NET应用程序的生命周期中扮演关键...
ASP.NET URL重写(URLRewriter)是一种技术,用于改变应用...`URLRewriter.dll`库提供了方便的工具,使得在ASP.NET环境中实现URL重写变得简单易行。通过理解其原理和应用,开发者可以更好地优化网站性能和用户体验。