老赵点滴


  先做人,再做技术人员,最后做程序员。
  我的理想:“让外国人看中国人写的技术书籍和文章”。Try as I might
posts - 287, comments - 10551, trackbacks - 137, articles - 6
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

  可能已经没有人会使用上一篇文章中的方法进行URL Rewrite了,因为提供URL Rewrite的组件早已铺天盖地了。

  ASP.NET级别的URL Rewrite组件的原理很简单,其实只是监听BeginRequest事件,并且根据配置来决定目标URL。在我之前接触过的项目中,发现使用URLRewriter作为URL Rewrite组件的频率非常高,我想可能是因为那是微软提供的东西吧。

  如果要使用URLRewriter,首先自然就是在web.config中配置一个HttpModule:

<httpModules>
  <add name="ModuleRewriter"
       type="URLRewriter.ModuleRewriter, URLRewriter" />
</httpModules>

  然后就是进行配置了(注:强烈建议使用configPath属性将配置提取成额外的文件,便于管理):

<configSections>
  <section name="RewriterConfig"
           type="URLRewriter.Config.RewriterConfigSerializerSectionHandler, URLRewriter" />
</configSections>
<RewriterConfig>
  <Rules>
    <RewriterRule>
      <LookFor>~/tag/([\w]+)/</LookFor>
      <SendTo>~/Tags.aspx?Tag=$1</SendTo>
    </RewriterRule>
  </Rules>
</RewriterConfig>

  正则表达式是一个非常了不得的东西,能匹配,能捕获。在上面的例子中,我们把符合LookFor条件的“/tag/xxx”重新定位到Tags.aspx页面上,并且将xxx作为Tag这个QueryString项的值,这样就能够在代码中通过HttpContext.Request.QueryString["Tag"]来获得该值了。

  URLRewriter的功能对于大多数应用来说已经足够了,但是我总是不喜欢。但如果非要问我不喜欢的原因,我也难说出个子丑寅卯来。可能仅仅是这个配置方式的问题吧。在使用URL Rewriter时,配置段往往会非常长,每个配置项需要从<RewriterRule>到</RewriterRule>共4行代码,一个规模不大的项目都很容易出现上百行的配置。“这也太XML了”,我想,为什么不用XML Attribute呢?这样每个配置项就能缩短为1行了——不过,这是题外话。

  所以如果我目前要做URL Rewrite,往往用的是Intelligencia出品的开源组件UrlRewriter.NET。虽然这个名字和前一个非常相似,但是功能却远超前者。该组件在使用上和URLRewriter比较接近(其实似乎所有的URL Rewrite组件都差不多),我们要做的也只是配置:

<configSections>
  <section name="rewriter"
           type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler,
                 Intelligencia.UrlRewriter" />
</configSections>
 
<rewriter>
  <rewrite url="^/User/(\d+)$" to="~/User.aspx?id=$1" processing="stop" />
  <rewrite url="^/User/(\w+)$" to="~/User.aspx?name=$1" processing="stop" />
</rewriter>
 
<system.web>
  <httpModules>
    <add name="UrlRewriter"
         type="Intelligencia.UrlRewriter.RewriterHttpModule,
               Intelligencia.UrlRewriter" />
  </httpModules>
</system.web>

  我们主要来看一下重写规则的配置项<rewriter />。与URLRewriter不同的是,UrlRewriter.NET使用了我喜欢的每规则一个节点的方式,这让整个项目的重写规则简洁不少。不过processing="stop"又是什么意思?这就要谈到UrlRewriter.NET在处理重写规则时的方法了。UrlRewriter.NET在找到一个匹配的重写规则时,不会就此停止,而会继续寻找其余的匹配项,最终生效的则是能够匹配当前请求的最后一个重写规则。如果我们需要UrlRewriter.NET在找到某个匹配项之后即生效,就需要将processing属性设为stop。例如在上面的配置里,如果“/User/”后紧跟着数字,则会使用用户ID进行查找,否则则认为当前所提供的是用户名。

  如果UrlRewriter.NET仅仅是因为配置上显得比较简洁,它与URLRewriter相比实在没有什么优势。但是UrlRewriter.NET的能力远不止此,我们刚才使用的其实只是它提供的Action之一,初次之外它还提供了许多Action:

  • if
  • unless
  • rewrite
  • redirect
  • setstatus
  • forbidden
  • gone
  • not-allowed
  • not-found
  • not-implemented
  • addheader
  • setcookie
  • setproperty

  光有Action还不够,UrlRewriter.NET还提供了Condition、Transform、Default Document、 Parser、Error Handler、Logger等功能,并且能够通过Expression来“表示”复杂的逻辑。这哪还是配置,简直就是编程了!没错,用UrlRewriter.NET完全就可以通过配置来将一些请求——回复的逻辑表示出来,这无疑为我们带来了很大的方便。在这里我不可能详细说明UrlRewriter.NET的方方面面,感兴趣的朋友可以从它官方网站所提供的Reference来一窥究竟。

  “得组件如此,夫复何求”,不过我在这里还是要推荐另外一个组件。因为在某些特殊情况下,UrlRewriter.NET还不能满足我们的要求。嗯?不是能自行扩展吗?没错,可是——先卖个关子,本系列的最后一篇中来说明这个问题。UrlRewriter.NET提供了ASP.NET层面上的URL Rewriter。如果要在IIS层面上进行URL Rewrite,那么还必须使用其他方式。ISAPI Rewrite是IIS层面上进行URL Rewrite的著名组件,很可惜这是个商业组件,需要我们使用美刀来购买。因此我在这里推荐另一个开源产品:IIRF(Ionic's Isapi Rewrite Filter)

  由于是在IIS层面进行URL Rewrite,IIRF的配置方式和UrlRewriter.NET是不同的。如果要使用IIRF,则需要将IsapiRewrite4.dll添加到Web Site的ISAPI Filter列表中:

Add ISAPI Filter

  IIRF是通过ini文件来配置的,IsapiRewrite4.ini与IsapiRewrite4.dll放在同样的目录中即可:

RewriteRule    ^/User/(\d+)$    /User.aspx?id=$1      [I, L]
RewriteRule    ^/User/(\w+)$    /User.aspx?name=$1    [I, L]

  IIRF的重写规则是“RewriteRule    <url-pattern>    <destination>    [<modifiers>]”,每个部分之间的空格数目没有限制,不过一定要是空格,而不能是Tab等其他空白字符。“url-pattern”和“destination”自不必多说,关键在于modifier。IIRF的modifier有不少,在这里我先只介绍上面用到的两个。“I”表示匹配时大小写无关,“L”的作用和UrlRewriter.NET里的processing="stop"类似,IIRF在找到该匹配项时立即生效,而不会继续查找下去。

  IIRF虽然是一个开源的组件,但是功能依然比较强大。尤其是结合了RewriteCond(Rewrite Condition)之后,可以实现比较复杂的重写规则。例如以下的配置则把UserAgent里包含Googlebot字样的根目录请求重写到某个特定的资源上:

RewriteCond    %{HTTP_USER_AGENT}    ^Googlebot.*
RewriteRule    ^/    $/Googlebot.html    [L]

  最后,我们来看一下两种组件Rewrite的区别。显然,最大的区别就在于它们是不同层面上的重写,下面的两幅示意图就描述了在两种情况下它们是如何将原本应该得到“404 Resource Not Found”结果的“/User/jeffz”请求重写至“/User/name=jeffz”的。

  首先是UrlRewriter.NET在ASP.NET层面上的URL Rewrite:

ASP.NET级别URL Rewrite

  接着是IIRF在IIS层面上的URL Rewrite:

ASP.NET级别URL Rewrite

  有了这两个组件,相信我们已经再也不需要其他东西来实现URL Rewrite了。

相关链接:

(1)IIS与ASP.NET

(3)在URL Rewrite后保持PostBack地址

(4)不同级别URL Rewrite的一些细节与特点

Feedback

#1楼    回复  引用  查看    

2008-01-13 00:42 by TerryLee      
URLRewriter在配置方式的确有些“莫名其妙”,记得好像还有一个叫做UrlRewriting.net的重写组件,这几个名字太像了...

对了还应该提一下URL重写时的图片和CSS路径问题

#2楼    回复  引用    

2008-01-13 00:44 by 在线代理 [未注册用户]
图片问题确实麻烦,不过俺现在用mod_rewrite了。

#3楼 [楼主]   回复  引用  查看    

2008-01-13 00:57 by Jeffrey Zhao      
@TerryLee
其实还行。
为了避免麻烦,一般所有的图片和CSS其实我都会用绝对路径引用的,比如“/Images/abc.jpg”。
而CSS里用到的图片,都是通过相对CSS路径来,所以问题其实不大。

#4楼 [楼主]   回复  引用  查看    

2008-01-13 00:58 by Jeffrey Zhao      
@在线代理
mod_rewrite不是apache的吗?

#5楼    回复  引用    

2008-01-13 01:10 by 3333333333 [未注册用户]
类似二级域名的重写,xxxx.cnblogs.com这种,UrlRewriter.NET可以实现么?

#6楼 [楼主]   回复  引用  查看    

2008-01-13 01:15 by Jeffrey Zhao      
@3333333333
没有尝试过,不过既然能够扩展,那么最多扩展一下,呵呵。

#7楼    回复  引用  查看    

2008-01-13 02:06 by Awen      
创建 rewriter 的配置节处理程序时出错: 未能从程序集“Intelligencia.UrlRewriter”中加载类型“Intelligencia.UrlRewriter.Configuration
出现这个问题哦!

#8楼 [楼主]   回复  引用  查看    

2008-01-13 02:57 by Jeffrey Zhao      
@Awen
恩,不能那样换行,把下面一行提到上面来吧。

#9楼 [楼主]   回复  引用  查看    

2008-01-13 02:58 by Jeffrey Zhao      
@Awen
文章里已经改好了。

#10楼    回复  引用  查看    

2008-01-13 03:43 by 李华星      
知道URL Rewriter, 没研究过, 看了LZ文章, 有些理解了

#11楼    回复  引用  查看    

2008-01-13 05:36 by Awen      
@Jeffrey Zhao
老赵也太强了吧,呵呵,这么晚,而且还发了第三篇,呵呵,我是睡了一个下午了!

#12楼    回复  引用    

2008-01-13 09:00 by 学习! [未注册用户]
我用DNT里的 IIS REwrite ,很方便好用,但不知道这是那个厂商提供的,是否涉及版权???

#13楼    回复  引用    

2008-01-13 13:16 by je [未注册用户]
如果我有个www.yourname.com:8081相关的URL,有没有什么IIS的REWRITE可以映射到www.yourname.com上的

#14楼 [楼主]   回复  引用  查看    

2008-01-13 13:56 by Jeffrey Zhao      
@je
这是服务器的概念,如果要实现这个,应该在服务器上设端口和主机头。

#15楼    回复  引用  查看    

2008-01-13 15:11 by Leem      
URLRewriter、URLRewriter.Net、UrlRewritingNet,还真是大同小异。不知道哪个比较合适。

#16楼    回复  引用  查看    

2008-01-14 08:05 by Ariel Y.      
@3333333333

可以

#17楼    回复  引用  查看    

2008-01-15 15:26 by Qingping&David      
支持转换为html/htm么?不要Rewrite后还是aspx?

#18楼 [楼主]   回复  引用  查看    

2008-01-15 23:01 by Jeffrey Zhao      
@Qingping&David
自然都可以

#19楼    回复  引用  查看    

2008-01-16 16:02 by Cat Chen      
@Jeffrey Zhao
apache的mod_rewrite很出名,不过另外一写开源的以mod形式支持ISAPI同类功能得Web服务器软件也有各自的mod_rewrite。(说不定就有一个IIS的mod_rewrite,哈哈。)

#20楼    回复  引用  查看    

2008-01-21 23:53 by legio      
有位能提供URLRewriter.Net的C#示例代码学习一下呀!好想知道它强大的功能呢

#21楼    回复  引用    

2008-01-29 16:27 by yma [未注册用户]
我用了开源的IIRF,怎么就是调不出来呢,郁闷啊,请博主指导

#22楼    回复  引用  查看    

2008-01-29 17:38 by Ariel Y.      
@yma
试试重启服务器和IIS,一般就好了

#23楼    回复  引用  查看    

2008-03-15 11:21 by 阿滨       
用vs2005的时候可以把www.abc.com/abc/xxx 映射到
www.abc.com/abc.aspx?tag=xxx
可是换到IIS上就无法找到文件.老赵这个是怎么回事啊
我用的是Intelligencia.UrlRewriter

#24楼 [楼主]   回复  引用  查看    

2008-03-16 12:35 by Jeffrey Zhao      
@阿滨
在IIS里设置Wildcard Mapping

#25楼    回复  引用    

2008-03-17 01:16 by Qingping [未注册用户]
@Jeffrey Zhao
Wildcard Mapping 那里设置??我用的是XP,IIS6.0.

#26楼 [楼主]   回复  引用  查看    

2008-03-17 11:45 by Jeffrey Zhao      
@Qingping
XP不是IIS 5.0吗?怎么设搜索一下就知道了。

#27楼    回复  引用    

2008-03-17 23:29 by Qingping [未注册用户]
@Jeffrey Zhao
多谢老赵,网上搜了一下,Wildcard Mapping 是II6+里面的新功能,我用的是XP II5.1,我本来想在XPpro sp2上安装IIS6.0,结果用了很多方法没有成功,看来只有在Windows Server2003上去体验这个功能了。。。

#28楼 [楼主]   回复  引用  查看    

2008-03-17 23:52 by Jeffrey Zhao      
@Qingping
IIS5也可以的,再某个地方设“*”就行了,我以前用过。

#29楼    回复  引用    

2008-03-27 17:22 by jone_linux [未注册用户]
我照你的写了,可是打入http://localhost:8083/User/12346确是没找到页面,为啥呢?

<configuration>
<configSections>
<section
name="rewriter" type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler,Intelligencia.UrlRewriter"
/>
</configSections>
<rewriter>
<rewrite url="^/User/(\d+)$" to="~/index_error.html" processing="stop" />
</rewriter>
<system.web>
<httpModules>
<add
name="UrlRewriter"
type="Intelligencia.UrlRewriter.RewriterHttpModule,Intelligencia.UrlRewriter"
/>
</httpModules>
</system.web>
</configuration>

#30楼 [楼主]   回复  引用  查看    

2008-03-27 21:33 by Jeffrey Zhao      
index_error.html不存在?

#31楼    回复  引用    

2008-03-28 07:52 by jone_linux [未注册用户]
@Jeffrey Zhao
当然是有的了,在根目录下的~~IIS不用设什么?我的WIN2003,IIS6

兄弟有QQ或MSN么,如果方便的话加我QQ:2561108或MSN:lily456789@hotmail.com,,单位要做这个,急啊~~~

#32楼 [楼主]   回复  引用  查看    

2008-03-28 10:38 by Jeffrey Zhao      
@jone_linux
iis6的isapi wildcard mapping设了吗?

#33楼    回复  引用    

2008-03-28 12:32 by jone_linux [未注册用户]
@Jeffrey Zhao
没有啊,我们用的是虚拟的空间,不能够对IIS进行设置啊,
aspx后缀也需要对IIS设置?
晕~~~

兄弟有QQ或MSN么,如果方便的话加我QQ:2561108或MSN:lily456789@hotmail.com,,单位要做这个,急啊~~~

#34楼    回复  引用    

2008-03-28 14:31 by jone_linux [未注册用户]
另外,
1、如果我要传二个以上的参数该怎么办?

#35楼 [楼主]   回复  引用  查看    

2008-03-28 18:14 by Jeffrey Zhao      
@jone_linux
我怀疑是因为IIS没有设wildcard mapping导致请求没有被asp.net处理,因此找不到文件,因为根本还没于进入rewrite阶段。这个和服务提供商确认一下吧。
// 我msn上人太多了,我们通过右下角的窗口联系吧。

#36楼 [楼主]   回复  引用  查看    

2008-03-28 18:14 by Jeffrey Zhao      
@jone_linux
无论几个参数,完全根据URL映射来实现。

#37楼    回复  引用  查看    

2008-04-06 19:48 by ZeroOne      
有个比较弱的问题想请教。
UrlRewriter.NET的文档里有一个介绍如何启用Debug Logger说明,地址是:
http://urlrewriter.net/index.php/support/reference/loggers/debug-logger/

我把配置加到config里面以后,怎么找不到显示Log的地方啊?
还是说只有出错的时候才会显示Log。

感谢。

#38楼 [楼主]   回复  引用  查看    

2008-04-07 01:11 by Jeffrey Zhao      
@ZeroOne
不好意思,这个我没有研究过。

#39楼    回复  引用  查看    

2008-05-26 09:36 by Kevin Li      
我按照你说的方法,在vs2008中调试 怎么还是没有重写的效果呢? 多谢指导

#40楼 [楼主]   回复  引用  查看    

2008-05-26 09:39 by Jeffrey Zhao      
@Kevin Li
哪个方法?

#41楼    回复  引用  查看    

2008-05-26 11:04 by Kevin Li      
就是这个 发现使用URLRewriter作

#42楼    回复  引用    

2008-06-22 09:45 by 安东 [未注册用户]
感谢老赵的博客,关注了很久了。。。。谢谢分享


我也是因为看了你的博客所以才用了url 重写的。。

现在发现一个问题,就是使用isapi_rewrite 或 IIRF 都无法在win2003 sp2 ii6 下加载,不知道是什么原因,目录权限都甚至都给了 everyone的所有控制权了,可是还是不能加载。

IIRF 我测试了:
IonicIsapiRewriter-1[1].2.14-bin.zip
IonicIsapiRewriter-1[1].2.12d-bin.zip
IonicIsapiRewriter-1[1].2.15a-bin.zip
IonicIsapiRewriter-2[1].0a-bin.zip

isapi_rewrite lite 2.9
但是在xp下就都可以加载。怎么也找不到问题

#43楼 [楼主]   回复  引用  查看    

2008-06-22 17:28 by Jeffrey Zhao      
@安东
我这里都是好好的

#44楼    回复  引用    

2008-06-23 17:06 by 安东 [未注册用户]
谢谢 老赵的回答

我这里在虚拟机wmware 6中测试是新装win2003 sp2 试验了好多次,不知怎么的突然可以用了,提示已经加载,优先级为低,但是我在服务器上装(不是虚拟机) 却怎么也不行,就是加载状态未知,无法加载,事件查看器中,提示无法加载。

我机器上安装了 mcafee 8.5i+sp5 mcafee Hip7.0

#45楼    回复  引用    

2008-06-24 00:10 by 安东 [未注册用户]
IIRF 采用 XXX/XXX/ 目录样式URL

IIRF 重写url后 打开页面中调用图片,css,js文件时要进行重写,这样影响性能。

如何让调用图片,css,js 不通过IIRF重写 过滤呢?来提升性能

#46楼 [楼主]   回复  引用  查看    

2008-06-24 09:32 by Jeffrey Zhao      
--引用--------------------------------------------------
安东: IIRF 采用 XXX/XXX/ 目录样式URL

IIRF 重写url后 打开页面中调用图片,css,js文件时要进行重写,这样影响性能。

如何让调用图片,css,js 不通过IIRF重写 过滤呢?来提升性能
--------------------------------------------------------
判断.jpg也总归要判断的,所以没有办法不进行一次处理。
这不会成为瓶颈的,放心。

#47楼    回复  引用    

2008-07-02 15:59 by Freeness [未注册用户]
楼主:这是我在ISAPI_Rewrite里面写的
RewriteCond Host: (?!www\.|test\.)([^.]+\.xxxx\.com
RewriteRule [/]+ /KtvBusinessInfo\.aspx\?id=$1 [I,L]

RewriteCond Host: (?!www\.|test\.)([^.]+\.xxxx\.com
RewriteRule [/]+ /BarBusinessInfo\.aspx\?id=$1 [I,L]

因为他们实现二级域名的参数都是一样的。但他们不是同一个模块。在查找的时候默认成了/KtvBusinessInfo\.aspx\?id=$1这个模块。请问有什么办法可以区别开他们是不一样的啊。

标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-01-13 16:36 编辑过
 
历史上的今天:

另存  打印