知识大全 在ASP.NET中实现Url Rewriting

Posted

篇首语:得意犹堪夸世俗,诏黄新湿字如鸦。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 在ASP.NET中实现Url Rewriting相关的知识,希望对你有一定的参考价值。

在ASP.NET中实现Url Rewriting  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  概要        分析如何使用微软提供的来对动态产生的URL地址进行网址重写 网址重写是实现一种截取网址请求并将其进行处理后重新指向到一个指定的网址的过程 作者本人在对各种实现网址重写的技术进行研究和探讨后得出的经验和方法 希望能对您有所帮助    内容简介        稍微花点时间看一看你做的网站里头的URL地址 你看到类似这样的地址吗x?EmpID= &type=summary ?也许你会出于某种目的把大量的页面文件从一个目录甚至一个网站转移到其他地方 而许多访问者出于个人兴趣或者研究目的之前就已经将原有网址收藏了起来 如果这时他从收藏夹打开该页面的时候发现这已经是坏链了 本文旨在介绍如何使用网址重写将那些 难看 的网址转换成比较有实际意义的网址 使其便于记忆 例如将x?EmpID= &type=summary转换成如下地址 dispEmployeeInfo/ /l 我们甚至发现 网址重写技术可以解决令人头疼的 错误 或者说它可以创建一个智能化的 错误解决方案        如上所述 网址重写是实现一种截取网址请求并将其进行处理后重新指向到一个指定的网址的过程 在网址重写执行的期间 相应处理程序处理被请求的网址 从中提取出相关的值 然后重新指向一个新的指定地址 例如 由于一次网站目录调整 原有的 /people/ 子目录下的所有网页全部移动到/info/employees/目录 原访问者从收藏夹或者其他什么地方点击链接发出访问/people/目录下的文件的请求时 你肯定希望他还是能通过原有地址看到和原来相同的页面 但实际上看到的却是网址重写指向的新目录下的相应文件        在老版本ASP中 使用网址重写技术的途径很少 要么写一个 ISAPI过滤器 要么购买第三方厂商提供的网址重写组件 然而在微软提供的ASP NET下你可以通过多种方法很简单地开发出自己的网址重写软件 以满足自己各种不同的需要 本文将和你一起讨论这门针对ASP NET开发人员的实现网址重写的技术 然后举一些网址重写实际应用的例子 在我们深入探讨网址重写技术的细节之前 我们先看一下日常使用网址重写技术实现的场景    网址重写的一般用途        创建一个数据操作的ASP NET程序最常见的就是一个aspx页面后面带上一些查询参数集合 例如在设计一个电子商务网站的时候 假定你设计了一项功能允许用户浏览待售的商品 为了更加方便操作 你设计了一个页面displayCategory aspx将商品按照给定的分类显示 那么该分类下的商品显示页面上应该在页面文件对应网址后面加上了一个商品分类的查询参数 例如用户要查询待售的 装饰品 在数据库中所有的装饰品数据对应的分类编号CategoryID的值为 那么用户会访问如下网址 x?CategoryID=        创建一个包含类似这样网址的网站最终有两种结果 首先从最终用户的角度来观察 x?CategoryID= 这个网址有些杂乱 可行性分析专家Jakob Neilson(主页 ) 建议选择网址显示方式时候考虑如下要求(参考网址 )        · 是否简短        · 是否易于输入        · 是否将站点结构形象化        · 是否具有隐蔽性 也就是让用户通过一个虚拟的看似有意义的导航地址访问指向该地址        我想还应该在上述列表中再增加一条 是否便于记忆 x?CategoryID= 这个地址没有一个地方符合Neilson标准的任何一条 也不便于记忆 当然 对于有经验的网络开发专家来说 他们很熟悉这种键值对构成的查询参数结构体系 然而对于普通用户来说输入这些带有参数的网址实在是太麻烦了        一种较好的方法就是使用一种比较直观且容易记忆的方式来将网址表示为 乍一看很容易就会推断这个网址所对应的内容极有可能会是显示装饰品(Widgets)信息 这个网址就变得更加容易记忆和传播!然后我告诉我的同事 请查看这个网址 不用我说第二遍 她可能一次就把地址敲到浏览器上了(你也可以在亚马逊()的网站上这样尝试一下) 很快就浏览器上就列出了装饰品(Widgets)的内容 这里 隐蔽性 表示 用户可以自行变更网址的结尾 例如输入 就能看到全部分类相关的商品列表或者列出所有相关商品分类目录列表        注 用上述简单的变更网址内容的方法来构思一下如今的比较流行的Blog网站生成的网址 例如 要查询 年 月 日所发的帖子 只需输入 即可 如果将网址裁减为 则显示 年 月份的帖子 同样将月份裁减掉得到 则显示出 年全年所发的帖子        网址重写技术除了用于将复杂的网址简单化之外 它还能用于处理因网站目录调整或者其他原因导致产生大量的无效链接和过期书签    当一个Web请求传送到IIS会发生什么?        在探讨如何实现网址重写这项技术之前 很有必要了解一下IIS是处理所接收的Web请求的机制 当一个Web请求到达IIS Web服务器时 IIS会根据所请求的文件后缀名来决定如何处理该请求 IIS可以处理诸如HTML页面 图片 静态内容 或者将请求转发给ISAPI应用程序 由该ISAPI应用程序处理后生成HTML静态内容返回给IIS 最后由IIS将请求结果发送回给客户端 (一个ISAPI应用程序就是一套编译好能随时在后台运行的类库 它的任务就是根据请求生成相关的内容 )        例如 如果IIS接收到一个对Info asp的请求 它会将该请求转交给 asp dll来处理 该ISAPI应用程序调出并执行所请求的ASP页面 然后把生成的HTML代码返回给IIS IIS最后把内容发送回请求客户端 对于ASP NET页面 IIS则将请求转交给名为 aspnet_isapi dll的ISAPI应用程序来处理 该ISAPI应用程序 调用托管的ASP NET工作进程来处理该请求 并将生成的HTML代码返回给请求客户端        你可以自定义IIS 将某一类扩展名映射到指定的ISAPI应用程序 图一显示了IIS管理工具中的应用程序配置对话框      图一.已配置的文件扩展名映射        关于对IIS如何管理所接收的请求的详细探讨有些超出本文内容 重要的是要了解 ASP NET引擎只负责处理对扩展名已经被正确配置映射到aspnet_isapi dll的网络请求

   

  用ISAPI过滤器来分析请求  除了将请求的文件扩展名映射到相应的ISAPI应用程序外 IIS还执行一些其他工作 例如 IIS还主动对发出请求的客户端用户进行授权 并判断已授权用户是否对其请求的文件拥有访问权限 在一个请求过程的全部生命期内 IIS的处理经历了几个阶段 在每一个阶段IIS都生成一个事件 而该事件可以被ISAPI过滤器实时操控的   如同ISAPI应用程序一样 ISAPI过滤器也是一块块安装在Web服务器上的非托管代码 ISAPI应用程序用于对所接收的特定文件类型做出响应 而ISAPI过滤器含有对IIS生成的事件做出响应的代码(contain Code) 甚至可以编辑进出的数据 ISAPI也含有众多应用程序 包括   · 权限控制与授权(Authentication and Authorization)  · 日志记录与监视(Logging and Monitoring)  · HTTP内容压缩(HTTP Compression)  · 网址重写(URL Rewriting)  本文所探讨的用ASP NET实现的网址重写技术就是 基于ISAPI过滤器用于网址重写的技术内容 然而我们仍然要讨论一下究竟是使用ISAPI过滤器还是使用ASP NET应用程序提供的技术来实现网址重写技术

  当一个请求传入ASP NET引擎的时候会发生什么?  ASP NET问世之前 在IIS Web服务器上的网址重写功能需要通过ISAPI过滤器来实现 自从这个家伙问世后我们就能通过ASP NET来实现URL重写了 因为ASP NET的解释引擎与IIS有极大的相似之处 产生这些相似性主要是因为 ASP NET   · 在处理接收的请求的生命期内也会产生事件   · 允许任意数量的HttpModule操控产生的事件 这与IIS中的ISAPI过滤器类似   · 将请求的资源委托给HttpHandler处理 这与IIS中的ISAPI应用程序类似   和IIS一样 在一个请求的整个生命期内 ASP NET对该请求的处理状态发出的状态改变信号引发相应的事件 例如 BeginRequest事件在ASP NET开始响应客户端请求之始引发 AuthenticateRequest事件在ASP NET确立用户身份后引发 当然还有诸如AuthorizeRequestResolveRequestCacheEndRequest等其它很多事件 这些 都是System Web HttpApplication类下的事件 更多信息请参考技术文档中的类HttpApplication概要   如上所述 可以创建ISAPI过滤器并用于相应IIS引发的事件 同理 ASP NET也提供了HttpModule用于响应ASP NET引擎引发的事件 一个ASP NET应用程序 通过配置可以拥有多个HttpModule ASP NET引擎 每处理一个请求 便初始化一个相应配置好的HttpModule 并允许它 针对请求处理期间引发的事件生成相应的事件委托 事实上ASP NET引擎 处理每一个请求调用大量的事件委托 FormsAuthenticationModule就是众多内嵌HttpModule中的一个 它 首先检查是否使用表单授权 如果是的话 它 将检查用户是否已授权 如果没有授权则自动把用户重定向到指定的登录页面 (即 在中可以直接记录并判别用户登录授权的问题了!)  回忆在IIS中 一项请求最后被转交给一个ISAPI应用程序处理 该应用程序针对每一项请求进行处理并返回相应的数据 例如 客户端发出一个访问经典ASP页面的请求 IIS将该请求转交给asp dll程序处理 asp dll针对该请求执行asp页面内容 并返回HTML编码 ASP NET也使用了类似的手法 ASP NET引擎在将这些HttpModule初始化后 判断并决定调用相应的HttpModule来处理该请求 (问 怎么程序操作Module)  所有通过ASP NET引擎解析的请求最终被送交一个HttpHandler或者HttpHandlerFactory(一个HttpHandler只是简单地返回一个用于处理该请求的HttpHandler的实例 )最终的委托呈现并响应所请求的HTML编码 并发送回IIS IIS则将HTML返回给请求客户端 ASP NET包含许多HttpHandler 例如 PageHandlerFactory是用于呈现ASP NET页面内容 WebServiceHandlerFactory用于呈现ASP NET Web服务的SOAP数据包 TraceHandler用于将ASP NET请求资源的HTML标记写入trace axd   图二描绘了一个针对ASP NET资源的请求所经过的处理流程 首先 IIS接收到该请求并将其转交给aspnet_isapi dll 其次 ASP NET引擎将一些HttpModule初始化 最后 最终的HttpHandler被调用 生成相应的标记语言 并将其返回给IIS 最终返回到请求客户端 图二.IIS和ASP NET对请求的处理过程  创建并注册自定义HttpModule和HttpHandler  创建自定义HttpModule的工作相对较简单 它包括一个实现当前接口的托管类 HttpModule必须实现System Web IHttpModule接口 同样HttpHandlerHttpHandlerFactory必须分别实现System Web IHttpHandler接口和System Web IHandlerFactory接口 有关创建HttpHandlerHttpModule的细节已经超出本书范围   一旦HttpModuleHttpHandler被创建后 必须向Web应用程序注册 如果要 向整个Web服务器HttpModuleHttpHandler只需简单的写入nfig文件 如果是 由指定的Web应用程序调用则需在该程序的nfig配置文件中添加几行XML标记

  例如 要向指定的Web应用程序注册HttpModuleHttpHandler 只需向该Web应程序的nfig配置文件中configuration\\System Web节中添加下列几行 <HttpModules> <add type= type name= name /></HttpModules>

  其中type属性为HttpModule的标识号和类库名称 name属性则为该模块取一个较为友好的名称方便 在Global asax调用 HttpHandlerHttpHandlerFactory则是 在nfig文件中configuration\\System Web节中添加<Handler>标记 例如 <Handlers> <add verb= verb path= path type= type /></HttpModules>  回忆上文 ASP NET对每一个接收到的请求指派相应的HttpHandler来处理并呈现相应内容 该指派决定于所接收请求的verb和path的内容 verb为HTTP请求的类型 GET或者POST path则为请求的文件的路径和文件名 如果我们打算用一个HttpHandler来处理所有GET类型和POST类型的并且文件扩展名为 scott的内容 可以在nfig相应配置节中加入下列标记 <Handlers> <add varb= * path= scott type= type /></Handlers>  其中 type是我们定义的HttpHandler的类型   注意 在注册HttpHandler的时候必须注意HttpHandler所使用的文件扩展名必须已经在IIS中做指向ASP NET引擎的映射 在上面 scott扩展名的例子中 如果我们所使用的 scott扩展名如果没有在IIS中做指向ASP NET引擎的映射的话 假定对foo scott文件发出请求 该请求 将导致IIS将foo scott文件内容直接呈现给客户端 为了能够让HttpHandler处理该请求 必须将 scott扩展名在IIS中做指向ASP NET引擎的映射 之后IIS才能正确地将 scott的请求转交给相应的HttpHandler

  实现网址重写  网址重写技术不但可以在IIS Web服务器一级通过ISAPI过滤器实现 而且还可以在ASP NET一级通过HttpModule或者HttpHandler实现 本文主要关注在ASP NET一级实现网址重写技术 所以此时不必关注在ISAPI应用程序中实现网址重写的技术细节 而且有很多第三方厂商提供的ISAPI过滤器 构建网址重写引擎  在ASP NET中实现网址重写很简单 只需调用System Web HttpContext类的RewritePath()方法即可 HttpContext类中包含有关于特定HTTP请求的HTTP规范信息 ASP NET引擎每接收到一个特定请求后便针对该请求创建一个特定的实例 这个类包含一些属性诸如 RequestResponse属性 分别提供对请求和响应的访问 ApplicationSession属性提供对Application变量和Session变量的访问 User属性提供对已授权用户信息的访问   在微软 NET Framework 版本中 RewritePath()方法接收一个新路径的简单字符串 在其内部HttpContext类的RewritePath(string)方法内在地更新Request对象的路径和查询参数 除了RewritePath(string)方法之外 NET Framework 版还提供了另外一些重载版本 其中一个重载版本接收三个输入字符串参数 这种交替的重载形式不仅仅只是设置Request对象的路径和查询参数这些属性 而是设置更深层的成员变量 这些成员变量用于为 PhysicalPathPathInfoFilePath属性计算Request对象值   为了实现ASP NET中的网址重写 我们需要创建一个HttpHandlerHttpModule用于   ·根据请求的路径决定所需要重写的路径   ·重写路径 如果需要的话可以调用RewritePath方法   以前文所构建的那个站点为例 可以通过/info/employee aspx?empID=EmployeeID来访问每一个雇员的信息 为了使这个网址更加地具有 隐蔽性 我们可能会使用更加容易理解的访问方式如 /people/雇员名 aspx 这里就有了一个网址重写的案例 当接收到对/people/ScottMitchell aspx的请求的时候 我们就得使用网址重写使得对该页面的请求被重写指向到先前使用的/info/employee?EmpID= 地址

  使用HttpModule来调用网址重写  在ASP NET一级来执行网址重写 既可以使用HttpHandler 也可以使用HttpModule 当使用HttpModule的时候 必须决定如果该网址需要被重写的话 究竟应该在整个请求的生命周期期间的那一个点来使用 乍一看着有些武断 但是这个决定以重大而且微妙的方式影响到你的应用程序 之所以作出对网址重写点的选择是因为内嵌的ASP NET HttpModule使用Request对象的属性值来完成自己的工作(回忆一下重写路径对Request对象的属性值的改变) 这些内嵌HttpModule和相应事件的密切关系列举如下

   HttpModule 事件 简介 FormsAuthenticationModuleAuthenticateRequest 判断用户是否已通过表单授权方式获取授权 如果没有的话则将用户重定向到指定的登录页面 FileAuthorizationModuleAuthorizeRequest 当使用Windows授权方式的时候 该HttpModule判断并确定该Microsoft Windows帐户是否对其请求的资源拥有足够的权限 UrlAuthorizationModuleAuthorizeRequest 检查并确认请求者是否对所访问的网址拥有权限 该Url授权可以在nfig文件的<authorization>和<location>元素中配置

  回想一下BeginRequest事件在AuthenticateRequest事件之前引发 而AuthenticateRequest事件又在AuthorizeRequest事件之前引发

  实现网址重写的一个较为安全的场合就是把它放在在BeginRequest事件中执行 这意味着如果要执行网址重写的话 在众多内嵌HttpModule运行的时候他已经完成了 这种途径的最终用途淋漓尽致地体现在表单验证上 当用户访问受限资源的时候 如果之前使用了表单验证 他会自动被重定向到指定的登录页面 在成功登录之后 用户被重定向回先前试图访问的受限制页面   如果把网址重写放在BeginRequest事件或者AuthenticateRequest事件中 在登录页面上执行提交后 该页面会将用户重定向到网址重写指定的页面 假定当用户在浏览器上敲入/people/ScottMitchell aspx地址 该地址是要被重定向到/info/employee aspx?EmpID= 的 如果该Web应用程序设定使用表单验证 当用户开始访问/people/ScottMitchell aspx的时候 该网址将重写指向/info/employee aspx?EmpID= 接着ForumAuthenticationModule启动 如果需要的话将用户重定向到登录页面 用户登录后重定向到的页面将是/info/employee aspx?EmpID= 这也是自从FormAuthenticationModule启动运行时所发出请求的页面 同上类似 当把网址重写放在BeginRequest事件或者AuthenticateRequest事件中运行的时候 UrlAuthenticationModule也发现了网址重写指向的网址 这意味着如果在该应用程序的nfig文件中<location>节为特定的网址配置特定的授权地址的话 你得引用重写所指向的网址   为了解决这个微妙的问题 一个可能就是把网址重写放在AuthorizeRequest事件中运行 但是在使用这种方法解决URL授权和表单授权的异常时又引入了一个新的缺陷 文件授权会失效 当使用Windows验证的时候 FileAuthorizationModule检查并验证已通过验证的用户是否拥有足够的权限访问特定的ASP NET页面   假定有一群用户并没有Windows级别的访问权限访问C:\\inetpub\\root\\info\\employee aspx 当这些用户试图访问/info/employee aspx?EmpID= 的时候 他们会得到未授权的错误 如果我们把网址重写放到AuthenticateRequest事件中运行 当FileAuthorizationModule验证该安全性设置的时候 他仍任人为被请求的文件是/people/ScottMitchell aspx 而这时该网址已经被重写了 因此FileAuthorizationModule会直接放行 让用户看到了网址重写指向的内容 /info/employee aspx?Empid=   那么什么时候在HttpModule调用网址重写合适呢?他决定于所使用的验证方式 当然如果不使用验证方式的话 那么无论是在BeginRequest事件 AuthenticateRequest事件还是AuthorizeRequest事件中调用网址重写没有多大区别 如果使用表单验证方式并且不使用Windows验证方式的话 把网址重写放入AuthorizeRequest事件委托中调用既可 如果使用Windows验证方式的话 把这项功能放入BeginRequest事件或者AuthenticateRequest事件调用就行了

  使用HttpHandler来调用网址重写  除了上面所述方法外 网址重写也可以放入HttpHandler或者HttpHandlerFactory中调用 HttpHandler是一个负责针对特定请求生成相应内容的类 而HttpHandlerFactory返回一个HTTP的实例 该实例针对特定请求生成相应内容   本节将着眼于为这些ASP NET页面创建一个网址重写的HttpHandlerFactory 创建HttpHandlerFactory必须实现IHTTPHandlerFactory接口 它包括一个GetHandler()方法 ASP NET引擎在初始化这些HttpModule后做出决定针对该请求调用相应的HttpHandler或者HttpHandlerFactory 在调用HttpHandlerFactory的时候 针对该Web请求以及随同的其他信息的HttpContext中经过的的HttpHandlerFactoryGetHandler()方法将被ASP NET引擎调用 HttpHandlerFactory必须返回一个能委托该请求的对象 并且该对象要能实现IHttpHandler接口   要通过一个HttpHandler来调用网址重写 可以先创建一个HttpHandlerFactory 它的GetHandler()方法检查所请求的网址并决定是否需要调用网址重写 如果要调用网址重写的话则调用前文所述的已通过检查的HttpContext对象的RewritePath()方法 最后该HttpHandlerFactory返回一个由类System Web UI PageParserGetCompiledInstance()方法返回的HttpHandler (这与内嵌于ASP NET页面的HttpHandlerFactoryPageHandlerFactory)的工作原理相同 )  在所有HttpModule被初始化后 HttpHandlerFactory就开始被实例化 把网址重写放在这些事件场所的最后一个里头调用的时候 也会碰到相同的问题 文件授权将会失效 如果非要依赖于Windows验证和文件验证的时候 你可能得使用HttpModule来调用网址重写了 下一章我们着眼于如何构建一个可重用的网址重写引擎 使用下文所提的这些示例均以真实案例作为参照 在作者主页上提供下载 先用用一个简单的网址重写的例子来探讨如何实现网址重写 紧接着将利用网址重写引擎中正则表达式的强大处理能力来展示真正 隐蔽 的网址重写技术!使用网址重写引擎实现简单的网址重写  为了便于在Web应用程序中实现网址重写 我构建了一个网址重写引擎 该引擎提供下列功能   ·可以在nfig文件中为页面开发者定义其所使用的网址重写引擎的规则   ·通过使用正则表达式来使所制定的网址重写规则具有更加强大的重写能力   ·能够通过简单配置即可在HttpModuleHttpHandler中使用网址重写   本节只探讨通过HttpModule来实现网址重写 要了解如何通过HttpHandler来实现网址重写请下载本文提供的代码 设置网址重写引擎的配置信息  我们来探讨一下在nfig中网址重写规则的配置节 首先必须在nfig文件中指出是否需要在HttpHandler或者HttpModule中调用网址重写 在nfig中 下文已经包含了两个已经被注释掉的配置节 <! <HttpModules> <add type= URLRewriter ModuleRewriter URLRewriter name= ModuleRewriter /></HttpModules> > <! <Handlers> <add verb= * path= * aspx type= URLRewriter RewriterFactoryHandler URLRewriter /></Handlers> >  被注释掉的<HttpModules>为配置使用HttpModule调用网址重写 注释掉的<Handler>为配置使用HttpHandler调用网址重写 不论配置使用<HttpModules>还是<Handlers>调用网址重写 除此之外还须配置网址重写规则 一条重写规则包括两项字符串 请求URL中的查找模式和针对该模式的匹配成功后的替换字符串 该信息在nfig文件中用下列标签描述

  <RewriterConfig> <Rules> <RewriterRule> <LookFor>pattern to look for</LookFor> <SendTo>String to replace pattern with </SendTo> </RewriterRule> <RewriterRule> <LookFor>pattern to look for</LookFor> <SendTo>String to replace pattern with </SendTo> </RewriterRule> </Rules></RewriterConfig>

  每一条规则都用一个<RewriterRule>元素表示 以<LookFor>节表示查询模式 当查询模式发现匹配字符串时便用<SendTo>节表示的字符串进行替换 这些规则从上到下进行查询匹配 如果找到一个匹配则按此规则执行网址重写 并且停止查找   配置<LookFor>节要使用正则表达式来进行字符串匹配和替换 (在此我们举一个例子来说明如何使用正则表达式来对字符串进行匹配和替换 )既然该查找模式是一个正则表达式 那么要注意避开对正则表达式保留字符串的直接使用 (正则表达式的保留字符串包括有 ? ^ $ 等等 可以通过在前面加上一个反斜线来引用这些保留字符 例如\\ 表示引用一个句点) 使用HttpModule来执行网址重写  创建一个HttpModule很简单 只要创建一个实现IHttpModule接口的类 该IHttpModule接口定义了两个方法   ·Init(HttpApplication) 该方法在HttpModule初始化时引发 通过该方法为HttpApplication事件调用相应的事件委托   ·Dispose() 当相应请求处理结束并发送回IIS调用此方法 通过此方法执行最终所有的清理和回收程序   为了更加方便地为网址重写创建HttpModule 从一开始我就创建一个抽象的基类(BaseModuleRewriter) 该类实现了IHttpModule接口 在Init(HttpApplication)事件中 它通过BaseModuleRewriter_AuthorizeRequest方法引发了HttpApplicationAuthorizeRequest事件 该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 = ; 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()方法以获取nfig文件中的网址重写规则的设置为起始 它通过循环访问各条网址重写规则 每次均获取当前规则中的LookFor属性 用正则表达式验证并判断是否查找是否对当前请求的网址是否有匹配

  如果发现一条匹配 将用当前规则的SendTo值对请求的路径执行一个正则表达式替换 替换后的地址通过参数的形式传给RewriterUtils RewriteUrl()方法 RewriterUtils是一个帮助类 它提供一对HttpModuleHttpHandler都可以使用的静态方法 RewriterUrl()方法只是简单地调用了HttpContext对象的RewritePath()方法   注意 你已经注意到了当执行正则表达式匹配和替换的时候调用了一个RewriterUtils ResolveUrl()方法 该帮助方法简单地替换了应用程序路径中 ~ 的所有实例   我们已经探讨了主要的部分 但是还有其它一些组件诸如将nfig文件中XML格式化了的网址重写规则反序列化至一个对象的类定义 通过HttpHandlerFactory实现网址重写的类定义等 本文最后三节将通过一些真实案例来探讨网址重写的技术 用网址重写引擎实现简单的网址重写  为了更好地示范网址重写引擎的运行 我们来建立一个ASP NET Web应用程序来实现简单的网址重写引擎 假定我们为一家在线销售各类商品的公司服务 这些产品划分为以下类别   分类编号(CategoryID) 分类名称(CategoryName)             饮料(Beverages)              调味品(Condiments)              工艺品(Confections)              日记本(Diary Products)        假定已经建立好一个名为ListProductsByCategoryID aspx的ASP NET页面文件 它通过查询参数获取一个分类编号 并根据此编号获取所有该分类下的所有商品 如果用户想浏览所销售的饮料类商品可以通过ListProductsByCategoryID aspx?CategoryID= 来访问 如果用户想浏览所销售的日记本类商品可以通过ListProductsByCategoryID aspx?CategoryID= 来访问 假定还有一个页面ListCategories aspx 它列出所有代售商品的分类编号   显然这里发现了一个网址重写的案例 对于用户来说他们所输入的地址不具有任何实际意义并且不具备任何 隐蔽性 倒不如使用网址重写引擎让用户去访问/Products/Baverage aspx地址 系统将该地址重写到ListProductsByCategoryID aspx?CategoryID= 我们可以在nfig文件中来完成网址重写任务 <RewriterConfig> <Rules> <! — Rules for products lister > <RewriterRule> <LookFor>~/Products/Baverage aspx</LookFor> <SendTo>~/ListProductsByCategoryID aspx?CategoryID= </SendTo> </RewriterRule> </Rules></RewriterConfig>  很明显地看到 搜索用户访问的路径是否匹配/Products/Baverage aspx 如果匹配的话 则将网址重写到/ListProductsByCategoryID aspx?CategoryID=

  注意 你会发现<LookFor>节点中避免直接在 Baverage aspx 中使用句点 是因为<LookFor>节点的值是正则表达式的匹配模式 在正则表达式中句点符号是一个特殊字符 它表示匹配任何一个字符 也就是说如果访问BaverageQaspx时也会发生匹配 为了避免发生这个句点引起的匹配我们得在该句点符号前面加上一个 \\ 表示引用句点符号   通过该规则定义 当用户访问/Products/Baverage aspx文件的时候 他们将看到代售的饮料类商品列表信息 图 为访问/Products/Baverage aspx地址时的浏览器截图 注意在浏览器中地址栏上显示的是用户输入的/Products/Baverage aspx地址 但是实际访问的地址却是网址重写后的/ListProductsByCategoryID aspx?CategoryID= (事实上 在服务器上根本就不存在/Products/Baverage aspx文件!)图三.网址重写后的对商品分类的请求  和/Products/Baverage aspx类似 下一步我们添加其它分类的重写规则 只需简单地在nfig文件中<Rules>中在添加其他<RewriteRule>节即可 该演示完整的重写规则集合请参考下载文档的nfig文件中的定义

  为了让该网址更具有 隐蔽性 如果让用户把/Products/Baverage aspx后面Baverage aspx一段截去 在浏览器中输入/Products/来浏览产品分类列表会更好一些 乍一看 这项任务微不足道 只需添加一条网址重写规则将/Products/映射到/ListCategories aspx即可 然而这里有一个微妙之处 你必须先创建一个/Products/目录 并在里面放一个空文件Default aspx   要认识为什么这些额外的步骤是必须的 先回顾一下前文 网址重写引擎是处于ASP NET一级的 也就是说 如果ASP NET没有获得处理请求的机会的话 网址重写引擎就不能对输入的网址请求作出判断 此外 IIS仅在请求文件包含相应扩展名时才将请求转交给ASP NET引擎 如果用户访问/Products/ IIS并不知道其扩展名是什么 于是它检查该目录下的文件看是否包含有默认首页文件名(Default aspx Default asp 等等 这些文件名在IIS管理工具对话框中Web服务器属性对话框中的文档标签中定义 )当然 如果/Products/目录不存在的话 IIS将返回一个HTTP 错误   所以我们需要创建一个/Products/目录并在该目录下额外创建一个空文件Default aspx IIS会检查该目录下的文件 发现有一个默认文件名Default aspx 于是将请求转交给ASP NET 这样 网址重写引擎才能生效 <RewriterRule> <LookFor>~/Products/Default aspx</LookFor> <SendTo>~ListCategories aspx</SendTo></RewriterRule>  通过该规则 用户访问/Products/Default aspx或者访问/Products/都可以看到如图四所示的产品分类列表 图四 在网址上添加 隐蔽性

   处理回送数据  如果要重写的网址上包含有服务器端Web Form并执行数据回送 当该Web Form回送数据时会暴露出真实的网址 也就是说 当用户访问/Products/Baverage aspx时 浏览器上地址栏显示的也是/Products/Baverage aspx 但是实际上是访问/ListProdutsByCategoryID aspx?CategoryID= 的内容 如果ListProductsByCategoryID aspx页面执行了数据回送的话 用户被数据回送定向给原始的/ListProductByCategoryID aspx?CategoryID= 页面上 而不是/Products/Baverage aspx页面 这虽然不是什么大问题 但是用户会觉察到点击一个按钮时网址发生了的变化 这也许会令人不安 因为如果出于网址安全的角度来说 直接把真实的网址暴露出来了 之所以发生这种现象的原因是当Web Form在呈现之时就明确地设置其action属性为当前Request对象中文件路径的值 当然 在Web Form呈现之时 从/Produts/Baverage aspx到/ListProductsByCategoryID aspx?CategoryID= 的网址重写就已经执行完毕了 这意味着Request对象所汇报的是当前用户所访问的地址是/ListProductsByCategoryID aspx?CategoryID= 这么看来 只需让该服务器端表单在呈现之时不呈现action属性即可解决问题了 (对浏览器来说 如果不设置action属性的话 那么在提交的时候将使用其默认值 )  然而不幸的是该Web Form不会允许你指定action属性 也不会允许你通过设置一些属性来达到禁用呈现action属性的目的 得自行继承System Web HtmlControls HtmlForm这个类 并重载该类的RenderAttribute()方法 明确指出该类不呈现acton属性   感谢继承这个强大的功能 使得我们很简单就获取了HtmlForm这个类下所有的功能定义 只需少量几行代码就达到所需目的 完整代码如下所示 namespace ActionlessForm public class Form:System Web UI HtmlControls HtmlForm protected override void RenderAttributes(System Web UI 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 this ClientID);   对RenderAttributes()方法重载的代码包含了原类HtmlFormRenderAttributes()方法全部的代码内容 只是简单地去掉了设置action属性这一节   当创建并编译了这个类后 将其添加到引用目录即可在该ASP NET Web应用程序中使用 为了将原有HtmlForm类替换 只需简单地在页面顶部添加下列代码 <% @ Register TagPrefix = skm Namespace = ActionlessForm Assembly = ActionlessForm %>  然后将<Form runat= server >标签替换为<skm:Form id= Form method= post runat= Server >  并将结束标记</Form>替换为<skm:Form>  你可以查看该文档相关下载中的ListProductsByCategoryID aspx文件中的自定义Web Form 该下载已经提供了完整的Visual Studio NET项目文件包   注意 如果你打算进行网址重写的地址不执行数据回送 则没有必要使用该自定义Web Form的类

  创建真正 隐蔽 的网址  上一节简单网址重写的示例展示了如何通过新的网址重写规则来轻松地配置网址重写引擎 本节将通过出众的正则表达式来展示网址重写的强大威力   时下正在流行Blog 很多人都拥有一个自己的Blog 不论你是否对Blog感到陌生 他们正在不断地更新自己的Blog页面 这些页面就像一个个人日记本一样 大多数Bloger只是简单地记录每天发生的事情 也有一些聚焦于某一主题 比如影评 球迷组织 电脑技术等   Blog可以在任何地点由作者进行更新 更新次数可以是一天多次 也可以是一周一两次 在Blog页面上只显示最近 条更新 但事实上所有的Blog软件都提供了存档记录 访客可以阅读其历史记录 有了 隐蔽 的网址 Blog应用程序将变得更加强大 假定你通过/ / / aspx来查询自己的Blog上的文章 你会为阅读到 年 月 日的Blog感到惊讶吗?此外你可能为了访问 年 月所有的Blog而将该地址裁减为/ / / 要访问 年所有的Blog 你可能会试着去访问/ /   在维护一个Blog的时候 如果将这种具有 隐蔽性 的网址提供给用户将会更好 实际上很多Blog引擎都提供了这种网址重写的功能 现在来看看这些是如何通过网址重写实现的   首先 我们需要一个页面能够分别按照年 月 日分别显示Blog的内容 假定现在已经做好了一个页面文件ShowBlogContent aspx 它能分别获取年 月 日的查询参数 要查看 年 月 日所发的帖子 我们可以访问/ShowBlogContent aspx?year= &month= &day= 要浏览 年 月的数据可以访问/ShowBlogContent aspx?year= &month= 要查询 年所有数据可以访问/ShowBlogContent aspx?year= (在下载文件中提供ShowBlogContent aspx源代码 )

  然后 当用户访问/ / / aspx时 我们需要将他访问的网址重写到/ShowBlogContent aspx?year= &month= &day= 上 这里需要制定三条网址重写规则 当指定访问年月日时 当指定访问年月时和当指定访问年时 <RewriterConfig> <Rules> <! Rules for Blog Content Displayer > <RewriterRule> <LookFor>~/(d )/(d )/(d ) aspx</LookFor> <SendTo>~/ShowBlogContent aspx?year=$ &month=$ &day=$ </SendTo> </RewriterRule> <RewriterRule> <LookFor>~/(d )/(d )/Default aspx</LookFor> <SendTo><![CDATA[~/ShowBlogContent aspx?year=$ &month=$ ]]></SendTo> </RewriterRule> <RewriterRule> <LookFor>~/(d )/Default aspx</LookFor> <SendTo>~/ShowBlogContent aspx?year=$ </SendTo> </RewriterRule> </Rules></RewriterConfig>  这些网址重写规则展示了正则表达式的强大威力 第一条规则按照(\\d )/(\\d )/(\\d )\\ aspx模式进行查找 通俗的说 它查找是否包含匹配xxxx/xx/xx aspx格式的字符串 其中x表示数字 每一组数字必须用圆括号括起来 这样可以在相应<SendTo>节内引用圆括号内的匹配字符串 我们可以使用$ $ $ 来分别引用前面匹配的圆括号组 其中$ $ $ 分别表示所匹配的第一 第二 第三个圆括号组   注意 由于nfig是XML格式的文档 所以在文本域内必须回避直接使用一些特殊字符 如 & <和>符号等 在第一条网址重写规则的<SendTo>节中用&amp来表示引用&符号 在第二条网址重写规则的<SendTo>节中用<![CDATA[ ]]>元素来表示其中所有的内容都是文本域 不再需要用转义字符来表示引用 这两种方法都可以实现同样的目的   下面图五 图六 图七都显示出网址重写的运行状况 这些数据都真实地摘自作者的Blog 图五显示 年 月 日的帖子 图六显示所有 年 月的帖子 图七显示 年所有帖子 图五 显示 年 月 日的帖子图六 显示 年 月所有的帖子

  图七 显示 年所有的帖子  注意 要使用网址重写引擎 强烈推荐在<LookFor>节中使用正则表达式

cha138/Article/program/net/201311/12964

相关参考

知识大全 在ASP.NET中自动给URL加上超级链接

在ASP.NET中自动给URL加上超级链接  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  作为一

知识大全 在ASP.NET中自动给URL地址加上超链接

在ASP.NET中自动给URL地址加上超链接  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  作为

知识大全 ASP.NET中获取URL重写前的原始地址

ASP.NET中获取URL重写前的原始地址  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在AS

知识大全 ASP.NET中获取URL重写前的原始地址详解

ASP.NET中获取URL重写前的原始地址详解  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!在AS

知识大全 ASP.NET中URL Rewrite的实现方法

ASP.NET中URLRewrite的实现方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  之

知识大全 ASP.NET MVC框架中的URL路径选择场景

ASP.NETMVC框架中的URL路径选择场景  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  A

知识大全 asp.net获取URL和IP地址

asp.net获取URL和IP地址  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  获取URL: 

知识大全 ASP.net实现无扩展名的URL重写

ASP.net实现无扩展名的URL重写  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  URL重写

知识大全 Asp.net关于对url编码的转化

Asp.net关于对url编码的转化  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  今天突然遇到

知识大全 asp.net用三种方法检测远程URL存在与否

asp.net用三种方法检测远程URL存在与否  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  用