在之前的文章裡我們已經談論了有關URL Rewrite的幾個主要的面向。在本系列的最後一篇文章中,我們就來討論不同等級URL Rewrite的一些細節與特點。
理論上說,IIS等級的URL Rewrite使用C或C++編寫,比使用託管程式碼編寫的ASP.NET等級URL Rewrite效能更高。但我認為這方面的差距在大部分情況下可以忽略不計,這種效能幾乎不可能成為效能瓶頸。因此選擇何種等級的URL Rewrite一般不會由您應用程式的效能要求來決定。那麼到底該使用哪種等級的URL Rewrite呢?在使用不同等級的URL Rewrite之後,我們又該注意點什麼呢?我在這裡談談我個人的看法。
雖說目前的URL Rewrite元件在功能上已經能夠滿足大部分的應用,但是在某些時候,我們的確還是會需要一些特殊的功能。例如根據網域名稱進行URL Rewrite,就目前的URL Rewrite元件來說,想要實現這個並不容易。商業化的ISAPI Rewrite目前已經可以支援這一點,可惜開源的UrlRewriter.NET和IIRF在這方面功能都有所不足。它們都是根據請求相對於該網站的路徑來匹配,至於請求的是哪個網域並不能作為匹配條件來使用。這就要求我們對URL Rewrite元件進行擴充。對大部分.NET開發人員來說,託管程式碼自然是開發首選,這時可能就要選擇ASP.NET等級的URL Rewrite重寫元件了。不過目前網路上能找到不少擴充的例子,無論是ASP.NET等級的UrlRewriter.NET或IIS等級的IIRF。
不過事實上,如果要實現上述功能,我們也可以分兩步驟進行。首先我們在IIS層級使用IIRF進行URL Rewrite,接著在ASP.NET層級作進一步的URL Rewrite。例如我們現在要實現將“ http://jeffz.domain.com/articles ”重寫為“/ArticleList.aspx?owner=jeffz”,就可以先在讓IIRF做第一次URL Rewrite,目的是將“ /articles」改寫至「/ArticleList.aspx」。
RewriteRule ^/Articles$ /ArticleList.aspx [I, L, U]
這樣,ASP.NET引擎就會直接接收到一個針對/ArticleList.aspx的請求了。然後在ASP.NET內部,我們可以作第二次的URL Rewrite(方便起見,我這裡還是在Global.asax裡寫,在專案中還是建議使用額外的HttpModule來實現)。
protected void Application_BeginRequest( object sender, EventArgs e)
{
HttpContext context = HttpContext .Current;
string host = context.Request.Url.Host;
string owner = host.Substring(0, host.IndexOf( '.' ));
context.RewritePath(context.Request.RawUrl + "?owner=" + owner);
}
經過兩次URL Rewrite,已經實現了我們想要的效果(在實際專案中,上面的程式碼不能直接使用,因為需要判斷是否有Query String等等)。
此外,ASP.NET層級的URL Rewrite只能在ASP.NET工作(顯然的事情),如果要讓URL Rewrite支援PHP,RoR等其他伺服器技術,就只能使用IIS等級的URL Rewrite了(或是其他伺服器技術提供的URL Rewrite功能)。
有些特殊字元是不允許出現在URL中的,或是一旦出現在URL裡以後,請求的含義就被改變了。例如我們需要對搜尋頁面進行URL Rewrite,將“/Search/xxx”重寫為“/Search.aspx?xxx”,然後可以根據問號後面的字串取得使用者提供的關鍵字。如果使用UrlRewriter.NET,我們就會使用以下的設定:
< rewriter >
< rewrite url = " ^/Search/(.+)$ " to = " ~/Search.aspx?$1 " processing = " stop " />
</ rewriter >
普通情況下,這個URL Rewrite工作正常。但是如果使用者使用「%」 作為關鍵字,情況就不一樣了,因為我們會收到如下的錯誤頁面提示:
這是因為URL中是不允許出現「%」的。大家可以去各種網站上嘗試著請求一些例如“ABC%25DEF”的路徑(“%25”之後即為“%”),大都能發現“400 Bad Request”錯誤。不過將「%」放在Query String裡倒是合法的──對阿,我們不是將keyword重寫到Query String了嗎?為什麼還是不行?這還是由於ASP.NET執行方式決定的。
Bad Request是在上圖的步驟3,也就是還在進行初始化的時候就被確定了。而我們的URL Rewrite是在第4步BeginRequest事件中才發生的。當請求中帶有非法字元時,我們根本還沒有機會進行URL Rewrite。
那我們要怎麼處理這個問題呢?在一般情況下,我們在客戶端將%去除也不會有太大問題(有些站點的確是這麼做的),但是如果非要保留呢?那就使用Query String來傳遞參數吧,或者我們也可以使用IIS等級的URL Rewrite。還是以IIRF為例:
RewriteRule ^/Search/(.+)$ /Search.aspx?$1 [I, L, U]
當請求被送到IIS之後(步驟一),並且在選擇應該交給哪個ISAPI執行(步驟二)之前就發生了URL Rewrite。經過了URL Rewrite之後的地址,其中的「%」已經轉移到了Query String中,這時候交由ASP.NET處理時自然已經合法了。
最後我們來討論出錯頁面的配置。例如,一般來說我們都會為應用程式配置一個404錯誤頁面,這樣使用者在存取不存在的資源時我們可以給他查看一個特定的頁面,而不是預設的錯誤提示。但在這一點上,不同等級的URL Rewrite就要使用不同的方法來設定。
如果我們使用了ASP.NET等級的URL Rewrite,一般來說我們已經在IIS裡設定了Wildcard Mapping,這樣任意的請求(包括html,jpg等)都會交由ASP.NET處理。如果請求了一個不存在的資源,404錯誤將由ASP.NET發出,因此404錯誤頁面應該在web.config中進行配置:
< customErrors mode = " On " defaultRedirect = " GenericErrorPage.htm " >
< error statusCode = " 404 " redirect = " FileNotFound.htm " />
</ customErrors >
如果我們使用了IIS等級的Url Rewrite,我們不會配置Wildcard Mapping。也就是說我們只有在Rewrite之後的位址為aspx(或其他原本就該交由ASP.NET ISAPI處理)的情況下,ASP.NET引擎才會開始運作。如果使用者請求了一個不存在的資源,那麼404錯誤將由IIS發出,這時候404錯誤頁面應該在IIS裡進行設定:
至此,有關URL Rewrite的話題已經討論完了。在實際開發中肯定還會遇到各種各樣不同的情況,但是只要理解了URL Rewrite方式的關鍵,按照程式運作的方式來思考,相信一般情況下不太會遇到難以處理的問題。