Asp.net 使用 System.Web.Routing 来实现 UrlRewrite

不管是隐藏信息还是搜索引擎友好,UrlRewrite 还是很有用的。我们可以在应用服务层实现 UrlRewrite,比如 Apache 或 IIS;也可以在应用程序层实现 UrlRewrite。Java 有很好的组件实现,.Net 中可以用 UrlRewriter.NET 来实现。看 Asp.Net MVC 引入 Routing 的概念,不过幸运的是我们不必搞个 MVC 项目也能享受到 Routing,那就是 .Net 3.5 已经为 MVC 做好准备的 System.Web.Routing。

差点忘了轻带一下什么是 UrlRewrite,比如说:

想访问 http://ip/test.aspx     你需要在地址栏里输入 http://ip/test,或者是 http://ip/test.do 就行了
想访问 http://ip/test.aspx?key1=val1&key2=val2,地址栏里输入 http://ip/test/val1/val2,或者是 http://test-val1-val2,自由的定义 URL 映射
或者地址栏里输入一个 Url,http://ip/rss-pro-10,直接访问的是个类,根本不需要一个 aspx 页面来处理请求。
比如访问某篇日志不再输入 http://ip/article.aspx?id=1989,而只需要输入 http://ip/article-1989.html 就能达到目的等等

以上想要输入的 Url 可以自由定义的,只要你能从中取出想要的信息,并把请求路由到实际的处理者(aspx或类) 便行。

我们知道在 Asp.Net 中要定义任意扩展名的请求可以使用 Handler,但它对于参数的重写有点困难,且对 IIS7 以前的版本还需加个扩展名的配置。而全功能的 UrlRewrite,确实可以用 UrlRewriter.NET 组件,只是如果你用的是 .Net 3.5 的话,又何必如此周折,直接上内置的 System.Web.Routing 便是。

下面具体例子来了解 System.Web.Routing 的整个工作过程与原理,可惜 .Net 的东西看不到源代码,很难更深入的,一直在这方面有点鄙视 MS。

需求是网站要向外提供 Rss Feed,Rss 是有过滤条件的,比如条目的类型,记录数。正常情况下我们通过 http://ip/rss.aspx?type=pro&num=10 来获得记录,而我们这里要实现的是用户可以用 http://ip/rss-pro-10 就能得到想要的 Rss 数据。

实现过程如下:

一:引入 System.Web.Routing 程序集

Add Reference,引入之后,在 Web.Config 的 <assemblies> 中可以看到添加了一行:

<add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/></assemblies>

二:加入 UrlRoutingModule 配置

System.Web.Routing 是基于 httpModules 来实现的,所以还应该在 Web.Config 的 <httpModules> 节点中加上:

<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

三:在程序启动时注册 Url 路由规则

这要在 Global.asax 中控制,在 Application_Start() 方法中注册路由条目。如果你理解 TCP/IP 网络的路由就很容易理解这里的路由,其实是一个道理。TCP/IP 网络的路由说的是数据包要去往哪里应该经过哪个网关,而这里的路由是指要访问哪个实际的资源应该走哪个 IRouteHandler 实例。

看 Global.asax 的注册路由的代码:

注册了两种 Url 规则的路由,第二个 Url 规则还用了正则表达式来约束,注意大括号里的参数在以后是可以得到的。符合规则的 Url 会转到与它相关联的 IRouteHandler 来处理。注意其中的 RouteValueDictionary 参数分别代表着什么,以及它们的声明办法,怎么设定正则表达式,以及与参数的对应。注册路由时还可以附加其他的约束条件,比如只处理 POST 请求等等。

四:IRouteHandler 实现

前面既然是为 Url 映射 IRouteHandler 实现,那么这里来看看 RssRouteHandler 是长什么样子的。

只要实现 IRouteHandler 接口,实现接口方法即可,接口方法需要返回的是一个 IHttpHandler 实现实例。并且参数 RequestContext 是在你的 IHttpHandler 实现类是用得着的。这样路由完成了从 Url -> IRouteHandler -> IHttpHandler 的层进,写过 HttpHandler 的人应该知道它可以处理页面能做的事情。那么来看看这里的 RssProvider 的简单实现吧:

五:IHttpHandler 实现

可以从重写的 Url 中按照规则获得请求参数,然后转给实际的资源去处理,或者直接在 HttpHandler 的 ProcessRequest() 方法中或再调用其他方法来玩成本次请求。

在 RssRouteHandler 为 RssProvider 这个 HttpHandler 实现类注入了 RequestContext  实例,你可以用这个实例从 Url 中获得想要的参数。

还有,在实际应用中最好能明确 IRouteHandler 和 IHttpHandler 实现类实例的复用情况,可选择适当的设计模式来保证。

六:配置 IIS6 使其他未知请求类型也由 Asp.Net 来处理

如果是在 Visual Studio 2008 的调试环境可以不作此配置,自动支持。对于 IIS 7 也不需要作特别的设置。XP 环境的 IIS6 和 Win2003 下的 IIS6 配置还略有不同:

Win2003 下 IIS6 配置:Default Web Site 的属性,Home Directory 标签页里,Configuation...,为 Wildcard application maps(order of implementation) Insert 一项,指向到 c:\windows\microsoft.net\framework\v2.0.50727\aspnet_isapi.dll,不勾选 Verify that file exists.

XP 下的 IIS6 配置:虚拟目录的属性页(不是 Default Web Site Properties 了), Virtual Directory 标签页中,点 Configuration 按钮,Maapings, 点 Add 按钮,Add/Edit Application Extensiona Mapping 窗口里,Executable 里选择 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll,Extension 里填 .*,然后不选 Check that file exists,确定就行了。

这样就完成了,通过 /rss-type-num 或 /rss/type/num/dateStart/dateEnd 就会执行到 RssProvider  的 ProcessRequest() 方法中,这样就完成了真实 Url 的重写,也能实现不需要 aspx 文件处理 Http 请求。

参考:1. Asp.net Url Routing代码分享
        2. System.Web.Routing入门及进阶 上篇
        3. System.Web.Routing入门及进阶 下篇

本文链接 https://yanbin.blog/asp-net-routing-urlrewrite/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

2 Comments
Inline Feedbacks
View all comments