asp.net下实现url重写

 

【原文地址】 Tip/Trick: Url Rewriting with ASP.NET
【原文发表日期】 Monday, February 26, 2007 9:27 PM
经常有人请我指导应该如何动态地 重写 ”URL ,以在他们的 ASP.NETweb 应用中发布比较干净的 URL 端点。这个博客帖子概述了几个方法,你可以用来在 ASP.NET 中干净地映射或重写 URL ,以及按照你自己的需求组织你的 URL 的结构。
为什么 URL 映射和重写很重要?
下面是开发人员想要对 URL 有更大的灵活性的最常见的场景:
1) 处理这样的情形:你要更改你的 web 应用中网页的结构,但你同时也要确保在你移动网页后,那些被人收藏的老 URL 不会成为死链接。重写 URL 允许你透明地将请求转交到新的网页地址而不出错。
2) 在象 Google Yahoo Live 这样的搜索引擎中提高你网站上网页的搜索相关性。具体地来说, URL 重写经常能使你在你网站上网页的 URL 里更加容易地嵌入关键词,这么做往往会增加别人点击你的链接的机会。从使用查询字符串参数到使用完全限定 (fully qualified) URL 也能在某些情形下提高你在搜索引擎结果中的优先顺序。使用强制 referring 链接使用同样的大小写 (same case) URL 入口 ( 譬如,使用 weblogs.asp.net/scottgu 而不是 weblogs.asp.net/scottgu/default.aspx) 的技术也能避免因跨越多个 URL 而造成的网页排名 (pagerank) 的降低 (avoid diluting your pagerank across multiple URLs) ,从而增加你的搜索结果。
在一个搜索引擎日渐驱动网站访问量的世界里,在你的网页排名上稍微得到一些提高就能给你的业务带来不错的投资回报 (ROI) 。逐渐地,这驱使开发人员使用 URL 重写以及其他 SEO( 搜索引擎优化 ) 技术来优化网站 ( 注, SEO 是个步调很快的空间,增加你的搜索相关性的建议月月在演变 ) 。想了解一些关于搜索引擎优化方面好的建议的话,我建议你阅读一下《 SSW Rules to Better Google Rankings (SSW的提高Google排名之要领) 》,以及 MarketPosition 关于《 how URLs can affect top search engine ranking (URL会如何影响顶级搜索引擎排名) 》的文章。
例程的 URL 重写场景
为这个博客贴子起见,我将假设我们将在一个应用里建造一套电子商务的产品目录网页,产品是按种类来组织的 ( 譬如,图书,录像, CD DVD 等等 )
让我们假定一开始我们有个网页叫 Products.aspx ,通过查询字符串参数接受一个类别名称,相应地过滤显示的产品。与这个 Products.aspx 网页对应类别的 URL 看上去象这样:
http://www.store.com/products.aspx?category=books
http://www.store.com/products.aspx?category=DVDs
http://www.store.com/products.aspx?category=CDs
 
但我们不想使用查询字符串来呈示每个类别,我们想修改应用,让每个产品类别对搜索引擎来说看上去象是一个独特的 URL ,并且在实际的 URL 中嵌入关键词 ( 而不是通过查询字符串参数 ) 。我们将在这个博客帖子剩下来的篇幅里,讨论一下达成这个目的我们可以采取的 4 种不同方法。
方法一:使用 Request.PathInfo 参数而不是查询字符串
我将示范的第一个方法根本不使用 URL 重写,而是使用 ASP.NET 中不太为人所知的一个特性, Request PathInfo 属性。为帮助解释这个属性的有用之处,考虑一下我们电子商店下面这些 URL 的情形:
http://www.store.com/products.aspx/Books
http://www.store.com/products.aspx/DVDs
http://www.store.com/products.aspx/CDs
你会在上面这些 URL 中注意到的一个东西是,他们不再含有查询字符串值,取而代之的是,类别参数的值是附加到 URL 上的,是以 Products.aspx 网页处理器名称之后的 / 参数 值的方式出现的。然后,一个自动化的搜索引擎爬虫 (search engine crawler) 会把这些 URL 解释成三个不同的 URL ,而不是一个 URL 带有三个不同的输入值 ( 搜索引擎是不理会文件扩展名的,只把它当作 URL 中的另一个字符而已 )
你也许很想知道怎么在 ASP.NET 中处理这个附加的参数的情形。好消息是,这非常简单。只要使用 Request PathInfo 属性就可以了,该属性返回 URL 中紧随 products.aspx 后面的那部分内容。所以,对上面这些 URL Request.PathInfo 会分别返回 “/Books” “/DVDs” ,和 “/CDs”( 万一你想知道的话, Request Path 属性返回 “/products.aspx” )
然后,你可以轻易地编写一个函数来获取产品类别,象这样 ( 下面这个函数去除前面的斜杠字符,只返回 “Books” “DVDs” ,或 “CDs”)
 
    Function GetCategory() As String

        If 
(Request.PathInfo.Length 0Then
            Return 
""
        
Else
            Return 
Request.PathInfo.Substring(1)
        
End If

    End Function
 
样例下载 :我建立的一个展示这个技术的样例应用可以 在这里下载 。这个样例和这个技术的很好的地方在于,为部署使用这个方法的 ASP.NET 应用,不需作任何服务器配置改动。在共享主机的环境里,这个技术也行之有效。
方法二:使用 HttpModule 实现 URL 重写
上述 Request.PathInfo 技术的替换方法是,利用 ASP.NET 提供的 HttpContext.RewritePath 方法。这个方法允许开发人员动态地重写收到的 URL 的处理路径,然后让 ASP.NET 使用刚重写过后的路径来继续执行请求。
譬如,我们可以选择向大众呈示下列 URL
 
http://www.store.com/products/Books.aspx
http://www.store.com/products/DVDs.aspx
http://www.store.com/products/CDs.aspx
 
在外界看来,网站上有三个单独的网页 ( 对搜索爬虫而言,这看上去很棒 ) 。通过使用 HttpContext RewritePath 方法,我们可以在这些请求刚进入服务器时,动态地把收到的 URL 重写成单个 Products.aspx 网页接受一个查询字符串的类别名称或者 PathInfo 参数。譬如,我们可以使用 Global.asax 中的 Application_BeginRequest 事件,来这么做:
    void Application_BeginRequest(object sender, EventArgs e) {

        
string fullOrigionalpath Request.Url.ToString();
        
        if 
(fullOrigionalpath.Contains("/Products/Books.aspx")) {
            Context.RewritePath(
"/Products.aspx?Category=Books");
        
}
        
else if (fullOrigionalpath.Contains("/Products/DVDs.aspx")) {
            Context.RewritePath(
"/Products.aspx?Category=DVDs");
        
}
    } 
 
手工编写象上面这样的编码的坏处是,很枯燥乏味,而且容易犯错。我建议你别自己写,而是使用网上现成的 HttpModule 来完成这项工作。这有几个你现在就可以下载和使用的免费的 HttpModule
·       UrlRewriter.net
·       UrlRewriting.net
这些模块允许你用声明的方式在你应用的 web.config 文件里表达匹配规则。譬如,在你应用的 web.config 文件里使用 UrlRewriter.Net模块 来把上面的那些 URL 映射到单个 Products.aspx 页上,我们只要把这个 web.config 文件添加到我们的应用里去就可以了 ( 不用任何编码 )
 
< ?xml  version ="1.0"?>

< configuration >

  
< configSections >
    
< section  name ="rewriter"   
             requirePermission
="false"  
             type
="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter"  />
  </
configSections >
  
  
< system.web >
      
    
< httpModules >
      
< add  name ="UrlRewriter"  type ="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter"/>
    </
httpModules >
    
  
</ system.web >

  
< rewriter >
    
< rewrite  url ="~/products/books.aspx"  to ="~/products.aspx?category=books"  />
    <
rewrite  url ="~/products/CDs.aspx"  to ="~/products.aspx?category=CDs"  />
    <
rewrite  url ="~/products/DVDs.aspx"  to ="~/products.aspx?category=DVDs"  />
  </
rewriter >   
  
</ configuration > 
 
上面的 HttpModule URL 重写模块还支持正则表达式和 URL 模式匹配 ( 以避免你在 web.config 文件里硬写每个 URL) 。所以,不用写死类别名称,你可以象下面这样重写匹配规则,把类别名称动态地从任何 /products/[ 类别 ].aspx 组合的 URL 里取出来:
 
  <rewriter>
    
<rewrite url="~/products/(.+).aspx" to="~/products.aspx?category=$1" />
  </
rewriter>  
 
这使得你的编码极其干净,并且扩展性非常之好。
样例下载 :我建立的一个使用 UrlRewriter.Net 模块展示这个技术的样例应用可以 在这里下载
这个样例和这个技术的很好的地方在于,为部署使用这个方法的 ASP.NET 应用,不需作任何服务器配置改动。在设置为中等信任安全等级 (medium trust) 的共享主机的环境里,这个技术也行之有效 ( 只要把文件 FTP/XCOPY 到远程服务器就可以了,不需要安装 )
方法三:在 IIS7 中使用 HttpModule 实现无扩展名的 URL 重写
上述的 HttpModule 方法在你要重写的 URL 含有 .aspx 扩展名或者包含另一个被设置为 ASP.NET 处理的扩展名的情形下一切都工作。你这么做的话,不需要任何特定的服务器配置,你只要把你的应用拷贝到远程服务器,它会正常工作的。
但有的时候,你要重写的 URL 要么拥有一个不为 ASP.NET 处理的文件扩展名 ( 譬如, .jpg .gif .htm) ,要么根本没有扩展名。譬如,我们也许要把这些 URL 呈示成公开的产品目录网页 ( 注意,它们没有 .aspx 扩展名 )
 
http://www.store.com/products/Books
http://www.store.com/products/DVDs
http://www.store.com/products/CDs
IIS5 IIS6 中,使用 ASP.NET 处理上面这样的 URL 不是很容易。 IIS 5/6 使得在 ISAPI 扩展 (ASP.NET 就是这样一个扩展 ) 里非常难以重写这些类型的 URLS 。你需要做的是使用 ISAPI 过滤器在 IIS 请求管道 (request pipeline) 的较早期实现重写。我将在下面的第四个方法里示范如何在 IIS5/6 实现这样的重写。
但好消息是, IIS 7.0 使得处理这类情形容易之极。你现在可以在 IIS 请求管道的任何地方执行一个 HttpModule ,这意味着你可以使用上面的 URLRewriter 模块 来处理和重写无扩展名的 URL( 甚至是带有 .asp .php ,或 .jsp 扩展名的 URL) 。下面示范了你在 IIS7 中该如何配置:
 
< ?xml  version ="1.0"  encoding ="UTF-8"?>

< configuration >

  
< configSections >
    
< section  name ="rewriter"  
             requirePermission
="false"  
             type
="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter"  />
  </
configSections >
  
  
< system.web >
      
    
< httpModules >
      
< add  name ="UrlRewriter"  type ="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter"  />
    </
httpModules >
    
  
</ system.web >

  
< system.webServer >

    
< modules  runAllManagedModulesForAllRequests ="true">
      
< add  name ="UrlRewriter"  type ="Intelligencia.UrlRewriter.RewriterHttpModule"  />
    </
modules >

    
< validation  validateIntegratedModeConfiguration ="false"  />

  </
system.webServer >

  
< rewriter >
    
< rewrite  url ="~/products/(.+)"  to ="~/products.aspx?category=$1"  />
  </
rewriter >
  
</ configuration >
 
注意一下 <system.webServer> <modules> 部分设置为 true runAllManagedModulesForAllRequests 属性。这个属性确保来自 Intelligencia UrlRewriter.Net 模块 ( 是在 IIS7 正式发布前编写的 ) ,会被调用,有机会重写到服务器的所有 URL 请求 ( 包括文件夹 ) 。上面的 web.config 文件非常酷之处在于:
1) 它在任何 IIS7 机器上都会工作,你不需要管理员在远程主机上启用任何东西,它也能在设置为中等信任安全等级 (medium trust) 的共享主机的环境场景下工作。
2) 因为我在 <httpModules> IIS7 <modules> 部分同时配置了 UrlRewriter ,我既能在 VS 内置的 web 服务器 ( Cassini) 中,也能在 IIS7 下使用同样的 URL 重写规则。两者完全支持无扩展名的 URL 重写。这使得测试和开发非常容易。
IIS 7.0 将在今年的晚些时候作为 Windows Longhorn 服务器的一部分发布,将在几个星期内随 Beta3 版本的发布支持 go-live 许可。由于添加到 IIS7 中的所有的新宿主 (hosting) 特性,我们预期主机供应商将会非常快地开始积极提供 IIS7 账号,这意味着你应该很快就可以开始利用上述的无扩展名的 URL 重写支持。我们将在 IIS7 RTM 时段里发布一个为微软所支持的 URL 重写模块,该模板是免费的,你可以在 IIS7 上使用,并且这模块将对你 web 服务器上的所有内容的高级 URL 重写场景提供很好的支持。
样例下载:我建立的一个使用 IIS7 UrlRewriter.Net 模块展示无扩展名 URL 重写技术的样例应用可以 在这里下载
方法四:在 IIS5 IIS6 中使用 ISAPIRewrite 来实现无扩展名的 URL 重写
如果你不想等到 IIS7 出来才利用无扩展名的 URL 重写,那么你最好的措施是使用 ISAPI 过滤器来重写 URL 。我知道有 2 ISAPI 过滤器方案,你也许要去看一下:
·       Helicon Tech's ISAPI Rewrite: 他们提供一个 99 美元 ( 可免费试用 30 ) ISAPI URL 重写产品完整版,以及一个免费的轻量级版本。
·       Ionic's ISAPI Rewrite: 这可以免费下载 ( 源码和可执行文件都可以下载 )
我没亲手用过上面的产品,虽然我听过到对这 2 个产品的好评。 Scott Hanselman Jeff Atwood 最近都写了精彩的博客贴子讲述使用这些产品的体验,同时提供了一些如何在这些产品中配置匹配规则的例子。 Helicon Tech ISAPI Rewrite 的规则使用跟 Apache mod_rewrite 同样的句法,譬如 (取自Jeff的博客贴子)
 
[ISAPI_Rewrite]
# fix missing slash on folders
# note, this assumes we have no folders with periods!
RewriteCond Host: (.*)
RewriteRule ([^.?]+[^.?/]) http/://$1$2/ [RP]

# remove index pages from URLs
RewriteRule (.*)/default.htm$ $1/ [I,RP]
RewriteRule (.*)/default.aspx$ $1/ [I,RP]
RewriteRule (.*)/index.htm$ $1/ [I,RP]
RewriteRule (.*)/index.html$ $1/ [I,RP]

# force proper www. prefix on all requests
RewriteCond %HTTP_HOST ^test/.com [I]
RewriteRule ^/(.*) http://www.test.com/$1 [RP]

# only allow whitelisted referers to hotlink images
RewriteCond Referer: (?!http://(?:www/.good/.com|www/.better/.com)).+
RewriteRule .*/.(?:gif|jpg|jpeg|png) /images/block.jpg [I,O]
 
一定要去读一下 Scott Jeff的贴子 以了解这些 ISAPI 模块的详情,以及你都能用它们做些什么。
注:使用 ISAPI 过滤器的一个坏处是,共享主机环境一般不允许你安装这样的组件,所以你要用它们的话,你要么需要一个专用的虚拟主机服务器,要么需要一个专用的主机服务器。但,如果你有一个主机计划允许你安装 ISAPI 的话,这会在 IIS5/6 下会提供最大的灵活性,让你过渡到 IIS7 推出为止。
URL 重写里处理 ASP.NET PostBack
大家在使用 ASP.NET 和重写 URL 时经常遇到的一个疑难杂症跟处理 postback 场景有关。具体地来说,当你在一个网页上放置一个 <form runat="server"> 控件时, ASP.NET 会自动地默认输出标识的 action 属性指向当前所在页面。当使用 URL 重写时,会出现这样的问题, <form> 控件显示的 URL 不是原先请求的 URL( 譬如, /products/books) ,而是重写过后的 URL( 譬如, /products.aspx?category=books) 。这意味着,当你做一个 postback 到服务器时, URL 不再是你原先干净利落的那个了。
ASP.NET 1.0 1.1 中,大家经常诉诸于继承 <form> 控件生成他们自己的控件,来正确地输出要使用的 action 属性。虽然这可以工作,但结果有点乱,因为这意味着你需要更新你所有的页面来使用这个另外的表单控件,而且有时在 Visual Studio 所见即所得设计器里也会遇上问题。
好消息是,在 ASP.NET 2.0 中,有个比较干净的诀窍你可以用来重写 <form> 控件的 action 属性。具体地来说,你可利用新的 ASP.NET 2.0控件适配器 扩展架构来定制控件的输出,用你提供的值来覆盖 action 属性的值。这不要求在你的 .aspx 页面里做任何编码改动 ,而只要在你的 /app_browsers 文件夹里添加一个 .browser 文件,注册使用一个控件适配类即可输出新的 action 属性。
 
你可在这里查看一个我创建的样例实现,其展示了该 如何实现与URL重写协作的表单控件适配器(Form Control Adapter) 。它在我上面使用的第一个 (Request.PathInfo) ,第二个方法 (UrlRewriter.Net 模块 ) 中都工作,它使用 Request RawUrl 属性获取原先没改写过的 URL 来显示。而在第四个方法 (ISAPIRewrite 过滤器 ) 中,你可以获取 ISAPI 过滤器保存在 Request.ServerVariables["HTTP_X_REWRITE_URL"] 中的原先的 URL 值。
我上面的 FormRewriter 类实现在标准的 ASP.NET ASP.NET AJAX 1.0 网页上应该都工作 ( 如果你遇上问题的话,告诉我一声 )
正确地处理 CSS 和图像引用
不少人在第一次使用 URL 重写时,有时会遇上一个疑难杂症,就是他们发现他们的图像和 CSS 样式表引用有时会停止工作。这是因为他们在 HTML 网页里有对这些文件的相对引用,当你开始在应用里重写 URL 时,你需要意识到浏览器经常会在不同的逻辑层次结构层上 (logical hierarchy levels) 请求文件,而不是实际存储在服务器上的东西。
譬如,如果我们上面的 /products.aspx 网页对 .aspx 网页里的 logo.jpg 有一个相对引用,但是通过 /products/books.aspx 这个 URL 来请求的,那么浏览器在显示网页时,将会发出一个对 /products/logo.jpg 的请求,而不是对 /logo.jpg 的请求。要正确地引用这个文件,确认你用根目录限定了 (root qualify)CSS 和图像引用 (“/style.css” ,而不是 “style.css”) 。对于 ASP.NET 控件,你也可以使用 “~” 句法从你应用的根目录来引用文件 ( 譬如, <asp:image imageurl="~/images/logo.jpg" runat="server"/>)
希望本文对你有所帮助 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值