在ASP.NET 2.0中實現URL重寫

來源:互聯網
上載者:User

URL重寫技術在今天已不是什麼新鮮的話題了,在Apache伺服器提供了名為mod_rewrite的URL重寫模組,而在IIS伺服器上,也有很多商業的ISAPI 篩選器模組可供使用。然而這對於我們,沒有很多的資金或使用的共用伺服器,使得以上的方法都不是最佳的解決方案。幸而ASP.NET給我們提供了強大的可擴充性,能讓我們自己定義頁面的訪問規則,很方便實現URL重寫。

  • 本文範例程式碼下載

在ASP.NET中實現URL重寫,需要建立HTTP模組(HttpModule)或HTTP處理常式(HttpHandler),通過調用HttpContext的RewritePath方法來近進行URL重寫。本篇文章使用的是HTTP模組做的樣本。

使用HTTP模組執行URL重寫

首先需要定義一個實現了IHttpModule介面的類。IHttpModule介面定義了兩個方法需要實現:

  • Init(HttpApplication)。此方法在初始化HTTP模組後觸發。在此方法中,您將把事件處理常式綁定到相應的HttpApplication事件。
  • Dispose()。當請求已完成並已發送回IIS時調用此方法。您應當在此處執行所有最終的清除操作。
   1:          public virtual void Init(HttpApplication app)
   2:          {
   3:              // WARNING!  This does not work with Windows authentication!
   4:              // If you are using Windows authentication, change to app.BeginRequest
   5:              app.AuthorizeRequest += new EventHandler(this.URLRewriter);
   6:          }

注意如果要使用表單身分識別驗證而不使用Windows身分識別驗證,請將URL重寫放在AuthorizeRequest事件處理常式中執行。如果要使用Windows身分識別驗證,請在BeginRequest或AuthenticateRequest事件進行過程中安排URL重寫。

在URLRewriter方法裡的第7行從設定檔裡讀取URL重寫資訊,進行處理,如對Regex的處理。如您對如何擴充標準的設定檔還不清楚,請看這篇Blog:擴充.NET 2.0標準設定檔

   1:          protected void URLRewriter(object sender, EventArgs e)
   2:          {
   3:              HttpApplication app = (HttpApplication) sender;
   4:              string requestedPath = app.Request.Path;
   5:          
   6:              // get the configuration rules
   7:              UrlsCollection rules = UrlsConfig.GetConfig().Urls;
   8:   
   9:              for (int i = 0; i < rules.Count; i++)
  10:              {
  11:                  // get the pattern to look for, and Resolve the Url (convert ~ into the appropriate directory)
  12:                  string lookFor = "^" + RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, rules[i].VirtualUrl) + "$";
  13:   
  14:                  Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);
  15:                  if (re.IsMatch(requestedPath))
  16:                  {
  17:                      string sendToUrl = RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, re.Replace(requestedPath, rules[i].DestinationUrl));
  18:                      RewriterUtils.RewriteUrl(app.Context, sendToUrl);
  19:                      break;
  20:                  }
  21:              }
  22:          
  23:          }

如果匹配,則調用RewriteUrl方法,將URL分解成路徑和查詢字串兩部分,以調用HttpContext.RewritePath方法來實現URL的重寫。其中對“URL資源的附加路徑資訊”(如:Http://www.microsoft.com/virdir/page.html/tail 的tail部分)未做處理,直接用String.Empty來表示,如您需要,可以自行擴充一下。

OK,到此為止,一個簡單的URL重寫程式就初步完成了,但還沒有大功告成,還有一個細節的問題需要我們處理一下,就是頁面回傳後又會在地址欄顯示出重寫前的地址,也就是真實的地址,影響美觀:)。有兩種方法可以解決這個問題:

  • 自訂一個繼承form控制項的控制項
   1:      public class Form : System.Web.UI.HtmlControls.HtmlForm
   2:      {
   3:          /// <summary>
   4:          /// The RenderAttributes method adds the attributes to the rendered &lt;form&gt; tag.
   5:          /// We override this method so that the action attribute is not emitted.
   6:          /// </summary>
   7:          protected override void RenderAttributes(HtmlTextWriter writer)
   8:          {
   9:              // write the form's name
  10:              writer.WriteAttribute("name", this.Name);
  11:              base.Attributes.Remove("name");
  12:   
  13:              // write the form's method
  14:              writer.WriteAttribute("method", this.Method);
  15:              base.Attributes.Remove("method");
  16:   
  17:              // remove the action attribute
  18:              base.Attributes.Remove("action");
  19:   
  20:              // finally write all other attributes
  21:              this.Attributes.Render(writer);
  22:   
  23:              if (base.ID != null)
  24:                  writer.WriteAttribute("id", base.ClientID);
  25:          }
  26:   
  27:      }

這個方法直接去掉了form的action屬性,所以頁面就直接回傳給自己了,能夠解決問題,但使用起來比較麻煩。想象一下在每個需要重寫URL的頁面都要去改寫form標記,夠崩潰的了。

  • 利用ASP.NET 2.0控制項適配器擴充架構來定製控制項的輸出

在ASP.NET 2.0中,有個比較乾淨的訣竅可以用來重寫<form>控制項的action屬性。具體地來說,利用新的ASP.NET 2.0控制項適配器擴充架構來定製控制項的輸出,用提供的值來覆蓋action屬性的值。這不要求在.aspx頁面裡做任何編碼改動,而只要在/app_browsers檔案夾裡添加一個.browser檔案,註冊使用一個控制項適配類即可輸出新的action屬性。

.browser檔案

   1:  <browsers>
   2:    <browser refID="Default">
   3:      <controlAdapters>
   4:        <adapter controlType="System.Web.UI.HtmlControls.HtmlForm"
   5:                 adapterType="URLRewriter.Form.FormRewriterControlAdapter" />
   6:      </controlAdapters>
   7:    </browser>
   8:  </browsers>
 

URLRewriter.Form.cs檔案

   1:      public class FormRewriterControlAdapter : System.Web.UI.Adapters.ControlAdapter
   2:      {
   3:          public FormRewriterControlAdapter()
   4:          {
   5:          }
   6:   
   7:          protected override void Render(HtmlTextWriter writer)
   8:          {
   9:              base.Render(new RewriteFormHtmlTextWriter(writer));
  10:          }
  11:      }
  12:   
  13:      public class RewriteFormHtmlTextWriter : HtmlTextWriter
  14:      {
  15:          public RewriteFormHtmlTextWriter(HtmlTextWriter writer)
  16:              : base(writer)
  17:          {
  18:              base.InnerWriter = writer.InnerWriter;
  19:          }
  20:          public RewriteFormHtmlTextWriter(System.IO.TextWriter writer)
  21:              : base(writer)
  22:          {
  23:              base.InnerWriter = writer;
  24:          }
  25:   
  26:          public override void WriteAttribute(string name, string value, bool fEncode)
  27:          {
  28:              //If the attribute we are writing is the "action" attribute, and we are not on a sub-control, 
  29:              //then replace the value to write with the raw URL of the request - which ensures that we'll
  30:              //preserve the PathInfo value on postback scenarios
  31:              if (name == "action")
  32:              {
  33:                  HttpContext context = HttpContext.Current;
  34:                  if (context.Items["ActionAlreadyWritten"] == null)
  35:                  {
  36:                      //We will use the Request.RawUrl property within ASP.NET to retrieve the origional 
  37:                      //URL before it was re-written.
  38:                      value = context.Request.RawUrl;
  39:                      //Indicate that we've already rewritten the <form>'s action attribute to prevent
  40:                      //us from rewriting a sub-control under the <form> control
  41:                      context.Items["ActionAlreadyWritten"] = true;
  42:                  }
  43:              }
  44:              base.WriteAttribute(name, value, fEncode);
  45:          }
  46:      }

直接將action屬性的值賦予成URL重寫後的地址,簡單又實惠,何樂而不為呢。

更正:因為我是在VS裡直接進行的測試,使用的是VS內建的那個輕量級伺服器(ASP.NET Development Server),而沒有在IIS下測試。通過劉島兄的留言,我看到了51aspx的轉載,並對這個錯誤進行了指正,謝謝諸位。

現在經過在IIS下測試,發現自訂的URL尾碼是需要在IIS裡映射到aspnet_isapi.dll的,我猜想在Development Server中應該是把所以的尾碼都映射到aspnet_isapi.dll上了。所以,如果您的空間是在共用的環境中,不太方便修改的話,直接使用aspx為尾碼,也不失為一個好方法。

 

參考文章:

  • HttpContext.RewritePath on MSDN
  • 技巧/訣竅:在ASP.NET中重寫URL
  • 在 ASP.NET 中執行 URL 重寫

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.