使用UrlRewriter進行Url重寫的完整解決方案
Setp 1:
下載UrlRewriter => http://urlrewriter.net/Setp 2:
將其添加到Web項目的Bin目錄下
Setp 3:
配置:打開web.config,在configSecions中添加sectionHandler:
RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter" />
添加這個section是為了它能夠處理web.config中的
<rewrite url=”~/lmh$” to=”~/Users.aspx?user=lmh” processing=”stop” />
</rewriter>
url是可以使用正則表達式的。比如上面的例子,就是將http://www.***.net/lmh重寫到http://www.***.net/Users.aspx?user=lmh,$在正則表達式中表示是串的結束,也就是說http://www.***.net/lmhe是不會被重寫到to后的地址的,如果把$去掉則可以。
Setp 4:
使rewriter生效:UrlRewriter是在HttpModule中做url重寫的,要使重寫生效,就得先把HttpModule添加到web.config中:
<add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter"/>
</httpModules>
Setp 5:
讓ReWriter有機會重寫Url: 當iis收到一個請求時,并不是都會扔給asp.net(aspnet_isapi.dll)來處理,比如靜態html,默認情況下,當請求html頁面時,iis直接就把結果拋給了客戶端,之所以.aspx頁面會被asp.net引擎處理,是因為在iis有進行處理程序映射,.aspx被映射到aspnet_isapi.dll,所以當iis收到請求時,先看后綴名,如果是aspx,那就把它交給aspnet_isapi.dll來處理。因為UrlRewriter是asp.net級別的重寫組件,所以,假如要想執行setp3中例子那樣的重寫,得先讓UrlRewriter有機會收到這個地址的請求才行(默認UrlRewriter是沒機會處理這個url的,因為iis收到這個地址的請求時,因為它沒有映射到aspnet_isapi.dll,所以會直接拋出404找不到的錯誤,因此,要替它做這個映射。打開iis,在屬性中有這一項,我們可以讓*映射到aspnet_isapi.dll,這樣所有的文件都交給asp.net來處理了,UrlRewriter也就有機會出手了。
如果用的是IIS7.0,則不用這么麻煩,整個Setp4可以簡化為:在web.config中的
這會保證所有的請求都會經過asp.net的這個Module。
現在,重寫就算基本完成了,但有幾個問題:
Problem 1:
圖片可能不顯示:如果進行Url Rewirte并且頁面中的圖片引用是使用相對路徑的話,很可能會發現圖片無效了,這是因為,假如/Users/lmh會被重寫為/Users.aspx?user=lmh,而Users.aspx上有一張圖片,放在相同目錄下:logo.gif,(Users.aspx中是<img src='logo.gif' />)那當請求/Users/lmh時,瀏覽器對logo.gif的請求的路徑將變成/Users/logo.gif,而實際上logo.gif是要用/logo.gif才能請求得到的,所以,為了保證Url rewrite后不會出現這個問題,需要使用<img src='/logo.gif' />,但是當使用UrlRewriter時,對于Css,如果代碼中是,而實際用Users/lmh去請求的話,會發現其實已經變成了,而圖片,如果是用的服務器控件的話,也可以繼續使用相對路徑,就不存在標題中的問題。
Problem 2:
Asp.net的postback會導致真實地址又被嚗光:還是setp3的例子,假設Users.aspx中有一個服務器按鈕控件,當第一次請求時,確實OK,但是一旦點擊了那個按鈕,地址欄又變成了http://www.***.net/Users.aspx?user=lmh,原因是asp.net的服務器form控件的action默認都是指定當前頁面地址的,雖然我們收到的請求是…/lmh,但經過UrlRewrite后,asp.net處理的已經是真實的地址:…/Users.aspx?user=lmh,所以在form被Render時,action會是../Users.aspx?user=lmh,那么,要解決這個問題,就是讓form的action的值也被render為請求的地址,這個網上已經有答案了,就是利用ControlAdapter(寫在App_Code中即可,不過為了重用,可以放到類庫項目中):
這段代碼是來自Jeffery Zhao的博客文章(我去掉了其中一些代碼,只保留了保證會工作的最基本代碼)。
需要說明的一點是:HtmlTextWriter有兩個WriteAttribute方法:
public virtual void WriteAttribute(string name, string value, bool fEncode)
public virtual void WriteAttribute(string name, string value)
重寫下面的那個WriteAttribute是不能成功的,必須重寫上面那個方法。為什么呢?先調試看看。
會發現如果重寫的是上面那個方法,則會有一次傳進來的name值是"action",如我所愿,而重寫下面那個方法則沒發現傳進來值是”action”的name參數。這是怎么搞的?
首先我們要知道,下面那個方法其實是簡單的調用了上面的WriteAttribute :
public virtual void WriteAttribute(string name, string value) {
WriteAttribute(name, value, false /*encode*/);
}
這是framework中的源碼。那么,我們所可以猜測到的,就是action這個屬性不是通過調用WriteAttribute(“action”, “…”)來渲染的,而是直接調用WrtiteAttribute(“action”, “…”, …),那我們就打開HtmlForm的源代碼看看吧(沒有源代碼的可以用Reflector看),找到HtmlForm.RenderAttributes(HtmlTextWrtier writer)方法,其中有幾行:
writer.WriteAttribute("method", Method);
Attributes.Remove("method");
// Encode the action attribute - ASURT 66784
writer.WriteAttribute("action", GetActionAttribute(), true /*encode*/);
Attributes.Remove("action");
我們重點看的是上面加粗并下劃線的那兩行,可以很清楚的看到,當渲染”method”屬性時,只是調用了
public virtual void WriteAttribute(string name, string value)
而渲染action屬性則是調用了
public virtual void WriteAttribute(string name, string value, bool fEncode)
那么,答案也就浮出水面了。
接下來,我們要讓這個Adapter起作用(上面之所以可以調試,是因為我已經讓其起作用了,只是還沒寫出來)。添加Asp.net Folder:App_Browses,新建一個browser文件:
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.HtmlControls.HtmlForm"
adapterType="FormRewriterControlAdapter"/>
</controlAdapters>
</browser>
</browsers>
因為上面的FormRewriterControlAdapter是寫在App_Code中的,所以不需要添加命名空間。
上面說的是一種防止postback后地址還原的辦法,還有一種辦法就是利用UrlRewriter自帶的form控件,這個方法還不需要寫這么多代碼:
首先,要先注冊控件:
然后用<rewriter:form runat="server"></form>代替掉原來的<form runat="server"></form>就可以了。
這么一來,使用UrlRewriter進行asp.net級別的UrlRewrite就弄好了。
![]()




}
}
浙公網安備 33010602011771號