|
在之前的文章里我們已經(jīng)談?wù)摿擞嘘P(guān)URL Rewrite的幾個主要的方面。在本系列的最后一篇文章中,我們就來討論一下有關(guān)不同級別URL Rewrite的一些細(xì)節(jié)與特點(diǎn)。
理論上說,IIS級別的URL Rewrite使用C或C++編寫,比使用托管代碼編寫的ASP.NET級別URL Rewrite性能要高。但是我認(rèn)為這方面的差距在大部分情況下可以忽略不計(jì),這種性能幾乎不可能成為性能瓶頸。因此選擇何種級別的URL Rewrite一般不會由您應(yīng)用程序的性能要求來決定。那么到底應(yīng)該使用哪種級別的URL Rewrite呢?在使用不同級別的URL Rewrite之后,我們又該注意點(diǎn)什么呢?我在這里談?wù)勎覀€人的看法。
對URL Rewrite功能上的要求
雖說目前的URL Rewrite組件在功能上已經(jīng)能夠滿足大部分的應(yīng)用,但是在某些時候,我們的確還是會需要一些特殊的功能。例如根據(jù)域名進(jìn)行URL Rewrite,就目前的URL Rewrite組件來說,想要實(shí)現(xiàn)這個并不容易。商業(yè)化的ISAPI Rewrite目前已經(jīng)可以支持這一點(diǎn),可惜開源的UrlRewriter.NET和IIRF在這方面功能都有所不足。它們都是根據(jù)請求相對于該站點(diǎn)的路徑來匹配,至于請求的是哪個域名并不能作為匹配條件來使用。這就要求我們對URL Rewrite組件進(jìn)行擴(kuò)展。對于大部分.NET開發(fā)人員來說,托管代碼自然是開發(fā)首選,這時可能就要選擇ASP.NET級別的URL Rewrite重寫組件了。不過目前網(wǎng)上能找到不少擴(kuò)展的例子,無論是ASP.NET級別的UrlRewriter.NET還是IIS級別的IIRF。
不過事實(shí)上,如果要實(shí)現(xiàn)上述功能,我們也可以分兩步進(jìn)行。首先我們在IIS級別使用IIRF進(jìn)行URL Rewrite,接著在ASP.NET級別作進(jìn)一步的URL Rewrite。例如我們現(xiàn)在要實(shí)現(xiàn)將“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內(nèi)部,我們可以作第二次的URL Rewrite(方便起見,我這里還是在Global.asax里寫,在項(xiàng)目中還是建議使用額外的HttpModule來實(shí)現(xiàn))。
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);
}
經(jīng)過兩次URL Rewrite,已經(jīng)實(shí)現(xiàn)了我們想要的效果(在實(shí)際項(xiàng)目中,上面的代碼不能直接使用,因?yàn)樾枰袛嗍欠裼蠶uery String等等)。
此外,ASP.NET級別的URL Rewrite只能在ASP.NET里工作(顯然的事情),如果要讓URL Rewrite支持php,RoR等其他服務(wù)器技術(shù),就只能使用IIS級別的URL Rewrite了(或者其他服務(wù)器技術(shù)提供的URL Rewrite功能)。
對URL中特殊字符的處理
有些特殊字符是不允許出現(xiàn)在URL中的,或者一旦出現(xiàn)在URL里以后,請求的含義就被改變了。例如我們需要對搜索頁面進(jìn)行URL Rewrite,將“/Search/xxx”重寫為“/Search.ASPx?xxx”,然后可以根據(jù)問號后面的字符串獲得用戶提供的關(guān)鍵字。如果使用UrlRewriter.NET,我們就會使用如下的配置:
<rewriter>
<rewrite url="^/Search/(.+)$" to="~/Search.ASPx?$1" processing="stop" />
rewriter>
普通情況下,這個URL Rewrite工作正常。但是如果用戶使用“%” 作為關(guān)鍵字,情況就不一樣了,因?yàn)槲覀儠盏饺缦碌腻e誤頁面提示:
這是因?yàn)閁RL中是不允許出現(xiàn)“%”的。大家可以去各種網(wǎng)站上嘗試著請求一些例如“ABC%25DEF”的路徑(“%25”之后即為“%”),大都能發(fā)現(xiàn)“400 Bad Request”錯誤。不過將“%”放在Query String里倒是合法的——對阿,我們不是將keyword重寫到Query String里了嗎?為什么還是不行呢?這還是由于ASP.NET執(zhí)行方式?jīng)Q定的。
Bad Request是在上圖的步驟3,也就是還在進(jìn)行初始化的時候就被確定了。而我們的URL Rewrite是在第4步BeginRequest事件中才發(fā)生的。當(dāng)請求中帶有非法字符時,我們根本還沒有機(jī)會進(jìn)行URL Rewrite。
那么我們怎么處理這個問題呢?在一般情況下,我們在客戶端將%去除也不會有太大問題(有些站點(diǎn)的確是這么做的),但是如果非要保留呢?那么就使用Query String來傳遞參數(shù)吧,或者我們也可以使用IIS級別的URL Rewrite。還是以IIRF為例:
RewriteRule ^/Search/(.+)$ /Search.ASPx?$1 [I, L, U]
當(dāng)請求被發(fā)送到IIS之后(步驟一),并且在選擇應(yīng)該交給哪個ISAPI執(zhí)行(步驟二)之前就發(fā)生了URL Rewrite。經(jīng)過了URL Rewrite之后的地址,其中的“%”已經(jīng)被轉(zhuǎn)移到了Query String中,這時候交由ASP.NET處理時自然已經(jīng)合法了。
出錯頁面配置
最后我們來討論出錯頁面的配置。例如,一般來說我們都會為應(yīng)用配置一個404錯誤頁面,這樣用戶在訪問一個不存在的資源時我們可以給他查看一個特定的頁面,而不是默認(rèn)的錯誤提示。但是在這一點(diǎn)上,不同級別的URL Rewrite就要使用不同的方法進(jìn)行配置。
如果我們使用了ASP.NET級別的URL Rewrite,一般來說我們已經(jīng)在IIS里設(shè)置了Wildcard Mapping,這樣任意的請求(包括html,jpg等)都會交由ASP.NET處理。如果請求了一個不存在的資源,404錯誤將由ASP.NET發(fā)出,因此404錯誤頁面應(yīng)該在web.config中進(jìn)行配置:
<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發(fā)出,這時候404錯誤頁面應(yīng)該在IIS里進(jìn)行配置:
至此,有關(guān)URL Rewrite的話題已經(jīng)討論完了。在實(shí)際開發(fā)中肯定還會遇到各種各樣不同的情況,但是只要理解了URL Rewrite方式的關(guān)鍵,按照程序運(yùn)行的方式來思考,相信一般情況下不太會遇到難以處理的問題。
相關(guān)鏈接:
NET技術(shù):重提URL Rewrite(4):不同級別URL Rewrite的一些細(xì)節(jié)與特點(diǎn),轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。