关于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)的降低,从而增加搜索结果。

在一个搜索引擎日渐驱动网站访问量的世界里,网页排名上稍微得到一些提高就能给业务带来不错的投资回报。这驱使开发人员使用URL重写以及其他SEO技术来优化网站(注,SEO是个步调很快的空间,增加你的搜索相关性的建议月月在演变)。

 

例子:用自定义IHttpModule实现URL重写

配置Web.config,继承IHttpModule,重写Init方法

web.config

----------------------

<?xml version="1.0" encoding="utf-8"?>

<configuration>

    <appSettings/>

    <connectionStrings/>

    <system.web>

      <httpModules>

        <add name="ErrorHandler" type="ErrorHandler,App_Code"/>

      </httpModules>

    </system.web>

</configuration>

---------------------
ErrorHandler.cs
---------
public class ErrorHandler:IHttpModule
{
public ErrorHandler()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
    public void Dispose()
    {
    }
    /// <summary>
    /// 用自定义IHttpModule实现URL重写
    /// </summary>
    /// <param name="context"></param>
    public void Init(HttpApplication context)
    {
        
        HttpContext _context = context.Context;
        
        string strUrl = _context.Request.RawUrl;
        if (strUrl != "/web/Default2.aspx")
        {
            //_context.RewritePath("Default2.aspx");
            _context.Response.Redirect("Default2.aspx");
        }
        
    }
}

URL重写例子

有个网页叫Products.aspx,通过查询字符串参数接受一个类别名称,相应地过滤显示的产品。

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属性。

http://www.store.com/products.aspx/Books
http://www.store.com/products.aspx/DVDs
http://www.store.com/products.aspx/CDs

这些URL中不含有查询字符串值,类别参数的值是附加到URL上的。一个自动化的搜索引擎爬虫会把这些URL解释成三个不同的URL,而不是一个URL带有三个不同的输入值 (搜索引擎是不理会文件扩展名的,只把它当作URL中的另一个字符而已)。

Request的PathInfo属性返回URL中紧随 products.aspx 后面的那部分内容。所以,对上面这些URL,Request.PathInfo会分别返回"/Books”,"/DVDs"和"/CDs"(Request.FilePath 属性返回"/products.aspx" )。编写一个函数来获取产品类别,象这样(这个函数去除前面的斜杠字符,只返回"Books”,"DVDs”或"CDs”):

if (Request.PathInfo.Length > 0 )
{
        string cardid =
 Request.PathInfo;
        cardid = cardid.Substring(1
);
        string
[] parms;
        if (cardid.IndexOf('_') > 0
)
        {
                parms = cardid.Split(new char[1] { '_'
 });
                foreach (string param in
 parms)
                {
                     Response.Write(param + "<br />"
);
                }
        }
}

此方法法应用于  可以实现如附加内容为/abc_123_def,分别获得3个信息用户数据的查询限定

使用这个方法的ASP.NET应用,不需作任何服务器配置改动。在共享主机的环境里也行之有效。 

方法二:使用HttpModule实现URL重写

在这里下载样例

利用ASP.NET提供的HttpContext.RewritePath方法。这个方法允许开发人员动态地重写收到的URL的处理路径,然后让ASP.NET使用刚重写过后的路径来继续执行请求。

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来完成。

  • URLRewriter.net
  • UrlRewriting.net

在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模式匹配:

   <rewriter>
     <rewrite url="~/products/(.+).aspx" to="~/products.aspx?category=$1" />
   </rewriter>  

这使得你的编码极其干净,并且扩展性非常之好。这个技术的好处在于不需作任何服务器配置改动。在设置为中等信任安全等级的共享主机的环境里也行之有效。

另外使用UrlRewriting.Net模板

<?xml version="1.0"?>
<configuration>
   <configSections>
     <section name="RewriterConfig"  requirePermission="false"   type="UrlRewriter.Config.RewriterConfigSerializerSectionHandler, UrlRewriter" />
   </configSections>
   <system.web>
     <httpModules>
       <add name="ModuleRewriter" type="URLRewriter.ModuleRewriter,URLRewriter"/>
     </httpModules>
   </system.web>
  <RewriterConfig>
    <Rules>
      <RewriterRule>
        <LookFor>~/site_intro/(.+).aspx</LookFor>
        <SendTo>~/site_intro.aspx?intro=$1</SendTo>
      </RewriterRule>
    </Rules>
  </RewriterConfig>

</configuration>
方法三:在IIS7中使用HttpModule 实现无扩展名的URL重写  

在这里下载样例

上述的HttpModule方法只能重写URL含有.aspx 扩展名或者包含一个被设置为ASP.NET处理的扩展名的情形下才工作。不需要任何特定的服务器配置,只要把应用拷贝到远程服务器就可以。当要重写的URL的扩展名不是为ASP.NET所能处理的(.jpg,.gif或 .htm)甚至根本没有扩展名。如:  

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就是这样一个扩展)里非常难以重写这些类型的URL。

IIS 7.0可以处理这类情形。可以在 IIS 请求管道的任何地方执行一个HttpModule,也可以使用上面的UrlRewriter来处理和重写无扩展名的URL(甚至.asp,.php或 .jsp 扩展名的URL):

<?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服务器,也可以在IIS7下使用同样的重写规则。两者完全支持无扩展名的URL重写。

方法四:在IIS5和IIS6中使用 ISAPIRewrite 来实现无扩展名的URL重写

[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]

注:使用ISAPI过滤器的一个坏处是,共享主机环境一般不允许你安装这样的组件,如果你有一个主机计划允许安装ISAPI,这会在IIS5/6下会提供最大的灵活性,让你过渡到IIS7推出为止。

正确地处理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"/>) 。 

在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值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值