常常有人請我指導應該如何動態地「重寫」URL,以在他們的ASP.NETweb應用中發佈比較乾淨的URL端點。這個博客帖子概述了幾個方法,你能夠用來在ASP.NET中乾淨地映射或重寫URL,以及按照你本身的需求組織你的URL的結構。php
下面是開發人員想要對URL有更大的靈活性的最多見的場景:css
1) 處理這樣的情形:你要更改你的web應用中網頁的結構,但你同時也要確保在你移動網頁後,那些被人收藏的老URL不會成爲死連接。重寫URL容許你透明地將請求轉交到新的網頁地址而不出錯。html
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),從而增長你的搜索結果。web
在一個搜索引擎日漸驅動網站訪問量的世界裏,在你的網頁排名上稍微獲得一些提升就能給你的業務帶來不錯的投資回報(ROI)。逐漸地,這驅使開發人 員使用URL重寫以及其餘SEO(搜索引擎優化 )技術來優化網站(注,SEO是個步調很快的空間,增長你的搜索相關性的建議月月在演變)。想了解一些關於搜索引擎優化方面好的建議的話,我建議你閱讀一 下《SSW Rules to Better Google Rankings (SSW的提升Google排名之要領)》,以及MarketPosition關於《how URLs can affect top search engine ranking (URL會如何影響頂級搜索引擎排名)》的文章。正則表達式
爲這個博客貼子起見,我將假設咱們將在一個應用裏建造一套電子商務的產品目錄網頁,產品是按種類來組織的(譬如,圖書,錄像,CD,DVD等等)。api
讓咱們假定一開始咱們有個網頁叫Products.aspx,經過查詢字符串參數接受一個類別名稱,相應地過濾顯示的產品。與這個Products.aspx網頁對應類別的URL看上去象這樣:瀏覽器
但咱們不想使用查詢字符串來呈示每一個類別,咱們想修改應用,讓每一個產品類別對搜索引擎來講看上去象是一個獨特的URL,而且在實際的URL中嵌入關 鍵詞(而不是經過查詢字符串參數)。咱們將在這個博客帖子剩下來的篇幅裏,討論一下達成這個目的咱們能夠採起的4種不一樣方法。 安全
方法一:使用Request.PathInfo 參數而不是查詢字符串服務器
我將示範的第一個方法根本不使用URL重寫,而是使用ASP.NET中不太爲人所知的一個特性,Request的PathInfo屬性。爲幫助解釋這個屬性的有用之處,考慮一下咱們電子商店下面這些URL的情形: 架構
你會在上面這些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」):
樣例下載:我創建的一個展現這個技術的樣例應用能夠在這裏下載。這個樣例和這個技術的很好的地方在於,爲部署使用這個方法的ASP.NET應用,不需做任何服務器配置改動。在共享主機的環境裏,這個技術也行之有效。
上述Request.PathInfo技術的替換方法是,利用ASP.NET提供的HttpContext.RewritePath方法。這個方法容許開發人員動態地重寫收到的URL的處理路徑,而後讓ASP.NET使用剛重寫事後的路徑來繼續執行請求。
譬如,咱們能夠選擇向大衆呈示下列URL:
在外界看來,網站上有三個單獨的網頁(對搜索爬蟲而言,這看上去很棒)。經過使用 HttpContext的RewritePath方法,咱們能夠在這些請求剛進入服務器時,動態地把收到的URL重寫成單個Products.aspx網 頁接受一個查詢字符串的類別名稱或者PathInfo參數。譬如,咱們可使用Global.asax中的 Application_BeginRequest事件,來這麼作:
手工編寫象上面這樣的編碼的壞處是,很枯燥乏味,並且容易犯錯。我建議你別本身寫,而是使用網上現成的HttpModule來完成這項工做。這有幾個你如今就能夠下載和使用的免費的HttpModule:
這些模塊容許你用聲明的方式在你應用的web.config文件裏表達匹配規則。譬如,在你應用的web.config文件裏使用UrlRewriter.Net模塊來把上面的那些URL映射到單個Products.aspx頁上,咱們只要把這個web.config文件添加到咱們的應用裏去就能夠了(不用任何編碼):
上面的HttpModule URL重寫模塊還支持正則表達式和URL模式匹配(以免你在web.config 文件裏硬寫每一個URL)。因此,不用寫死類別名稱,你能夠象下面這樣重寫匹配規則,把類別名稱動態地從任何/products/[類別].aspx組合的 URL裏取出來:
這使得你的編碼極其乾淨,而且擴展性很是之好。
樣例下載:我創建的一個使用UrlRewriter.Net模塊展現這個技術的樣例應用能夠在這裏下載。
這個樣例和這個技術的很好的地方在於,爲部署使用這個方法的ASP.NET應用,不需做任何服務器配置改動。在設置爲中等信任安全等級 (medium trust)的共享主機的環境裏,這個技術也行之有效 (只要把文件FTP/XCOPY到遠程服務器就能夠了,不須要安裝)。
上述的HttpModule方法在你要重寫的URL含有.aspx 擴展名或者包含另外一個被設置爲ASP.NET處理的擴展名的情形下一切都工做。你這麼作的話,不須要任何特定的服務器配置,你只要把你的應用拷貝到遠程服務器,它會正常工做的。
但有的時候,你要重寫的URL要麼擁有一個不爲ASP.NET處理的文件擴展名(譬如, .jpg, .gif, 或 .htm),要麼根本沒有擴展名。譬如,咱們也許要把這些URL呈示成公開的產品目錄網頁(注意,它們沒有 .aspx 擴展名):
在 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中該如何配置:
注意一下<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重寫技術的樣例應用能夠在這裏下載。
若是你不想等到IIS7出來才利用無擴展名的URL重寫,那麼你最好的措施是使用ISAPI過濾器來重寫URL。我知道有2個ISAPI過濾器方案,你也許要去看一下:
我沒親手用過上面的產品,雖然我聽過到對這2個產品的好評。Scott Hanselman和 Jeff Atwood 最近都寫了精彩的博客貼子講述使用這些產品的體驗,同時提供了一些如何在這些產品中配置匹配規則的例子。Helicon Tech的ISAPI Rewrite的規則使用跟 Apache的mod_rewrite一樣的句法,譬如(取自Jeff的博客貼子):
必定要去讀一下Scott和Jeff的貼子以瞭解這些ISAPI 模塊的詳情,以及你都能用它們作些什麼。
注:使用ISAPI過濾器的一個壞處是,共享主機環境通常不容許你安裝這樣的組件,因此你要用它們的話,你要麼須要一個專用的虛擬主機服務器,要麼 須要一個專用的主機服務器。但,若是你有一個主機計劃容許你安裝ISAPI的話,這會在IIS5/6下會提供最大的靈活性,讓你過渡到IIS7推出爲止。
你們在使用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網頁上應該都工做(若是你趕上問題的話,告訴我一聲)。
很多人在第一次使用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"/>) 。
出處:http://www.cnblogs.com/ajunForNet/archive/2012/05/19/2509212.html