国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
在 ASP.NET 中執(zhí)行 URL 重寫(xiě)
發(fā)布日期: 8/23/2004 | 更新日期: 8/23/2004
Scott Mitchell
4GuysFromRolla.com
適用范圍:
Microsoft? ASP.NET
摘要:介紹如何使用 Microsoft ASP.NET 執(zhí)行動(dòng)態(tài) URL 重寫(xiě)。URL 重寫(xiě)是截取傳入 Web 請(qǐng)求并自動(dòng)將請(qǐng)求重定向到其他 URL 的過(guò)程。討論實(shí)現(xiàn) URL 重寫(xiě)的各種技術(shù),并介紹執(zhí)行 URL 重寫(xiě)的一些實(shí)際情況。
下載本文的源代碼。
本頁(yè)內(nèi)容
引言
URL 重寫(xiě)的常見(jiàn)用法
請(qǐng)求到達(dá) IIS 時(shí)將會(huì)發(fā)生什么情況
實(shí)現(xiàn) URL 重寫(xiě)
構(gòu)建 URL 重寫(xiě)引擎
使用 URL 重寫(xiě)引擎執(zhí)行簡(jiǎn)單的 URL 重寫(xiě)
創(chuàng)建真正“可刪節(jié)”的 URL
結(jié)論
參考資料
引言
讓我們花點(diǎn)時(shí)間來(lái)看一下網(wǎng)站上的一些 URL。您是否發(fā)現(xiàn)一些類(lèi)似于 http://yoursite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&type=summary 的 URL?或者,您可能將一系列網(wǎng)頁(yè)從一個(gè)目錄或網(wǎng)站移動(dòng)到另一個(gè)目錄或網(wǎng)站,結(jié)果導(dǎo)致已將舊 URL 用作書(shū)簽的訪(fǎng)問(wèn)者斷開(kāi)鏈接。在本文中,我們將了解如何通過(guò)將 http://yoursite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&type=summary 替換為類(lèi)似于 http://yoursite.com/people/sales/chuck.smith 的網(wǎng)址,使用 URL 重寫(xiě)將那些冗長(zhǎng)的 URL 縮寫(xiě)為富有意義且容易記憶的 URL。我們還將了解如何將 URL 重寫(xiě)用于創(chuàng)建智能 404 錯(cuò)誤。
URL 重寫(xiě)是截取傳入 Web 請(qǐng)求并自動(dòng)將請(qǐng)求重定向到其他資源的過(guò)程。執(zhí)行 URL 重寫(xiě)時(shí),通常會(huì)檢查被請(qǐng)求的 URL,并基于 URL 的值將請(qǐng)求重定向到其他 URL。例如,在進(jìn)行網(wǎng)站重組而將 /people/ 目錄下的所有網(wǎng)頁(yè)移動(dòng)到 /info/employees/ 目錄中時(shí),您可能希望使用 URL 重寫(xiě)來(lái)檢查 Web 請(qǐng)求是否指向了 /people/ 目錄中的文件。如果請(qǐng)求指向 /people/ 目錄中的文件,您可能希望自動(dòng)將請(qǐng)求重定向到 /info/employees/ 目錄中的同一文件。
使用傳統(tǒng)的 ASP,應(yīng)用 URL 重寫(xiě)的唯一方法是編寫(xiě) ISAPI 篩選器,或者購(gòu)買(mǎi)提供 URL 重寫(xiě)功能的第三方產(chǎn)品。但是,使用 Microsoft? ASP.NET,您可以通過(guò)很多方法來(lái)輕松地創(chuàng)建您自己的 URL 重寫(xiě)軟件。本文討論了可供 ASP.NET 開(kāi)發(fā)人員實(shí)現(xiàn) URL 重寫(xiě)的各種技術(shù),然后討論了 URL 重寫(xiě)的一些實(shí)際使用情況。在深入討論 URL 重寫(xiě)的技術(shù)細(xì)節(jié)之前,讓我們先看一些可以使用 URL 重寫(xiě)的日常情景。
返回頁(yè)首
URL 重寫(xiě)的常見(jiàn)用法
創(chuàng)建數(shù)據(jù)驅(qū)動(dòng)的 ASP.NET 網(wǎng)站時(shí),通常會(huì)產(chǎn)生一個(gè)單個(gè)的網(wǎng)頁(yè),該網(wǎng)頁(yè)基于查詢(xún)字符串參數(shù)顯示數(shù)據(jù)庫(kù)數(shù)據(jù)的子集。例如,在設(shè)計(jì)電子商務(wù)站點(diǎn)時(shí),您的任務(wù)之一便是允許用戶(hù)瀏覽待售產(chǎn)品。為此,您可以創(chuàng)建一個(gè)名為 displayCategory.aspx 的頁(yè)面,該頁(yè)面將顯示給定類(lèi)別的產(chǎn)品。可以通過(guò)查詢(xún)字符串參數(shù)來(lái)指定要查看的該類(lèi)別的產(chǎn)品。也就是說(shuō),如果用戶(hù)要瀏覽待售的 Widget 產(chǎn)品,并且所有 Widget 產(chǎn)品的 CategoryID 均為 5,則用戶(hù)可以訪(fǎng)問(wèn)以下網(wǎng)址:http://yousite.com/displayCategory.aspx?CategoryID=5。
創(chuàng)建具有此類(lèi) URL 的網(wǎng)站有兩點(diǎn)不足:首先,從最終用戶(hù)的角度考慮,URL http://yousite.com/displayCategory.aspx?CategoryID=5 比較雜亂??捎眯詫?zhuān)家Jakob Neilsen建議遵循以下標(biāo)準(zhǔn)來(lái)選擇 URL:
?
簡(jiǎn)短。
?
易于鍵入。
?
可以看出站點(diǎn)的結(jié)構(gòu)。
?
“可刪節(jié)”,允許用戶(hù)通過(guò)刪除 URL 的組成部分來(lái)瀏覽站點(diǎn)。
我還要增加一條標(biāo)準(zhǔn),即,URL 應(yīng)該便于記憶。URL http://yousite.com/displayCategory.aspx?CategoryID=5 不符合 Neilsen 的任何標(biāo)準(zhǔn),也不容易記住。要求用戶(hù)鍵入查詢(xún)字符串值將使 URL 的鍵入變得非常困難,并且只有了解查詢(xún)字符串參數(shù)的用途及其名稱(chēng)/值對(duì)結(jié)構(gòu)的富有經(jīng)驗(yàn)的 Web 開(kāi)發(fā)人員才能夠?qū)?URL 進(jìn)行“刪節(jié)”。
較好的方法是允許使用切合實(shí)際且容易記憶的 URL,如 http://yoursite.com/products/Widgets。只要看一眼 URL,您便可以推斷出將要顯示的內(nèi)容 -- 有關(guān) Widget 的信息。此 URL 也很容易記住和共享。我可以告訴我的同事“請(qǐng)查看 yoursite.com/products/Widgets,”,她可能無(wú)需再次問(wèn)我 URL 是什么即可打開(kāi)該頁(yè)面。(嘗試一下,您只需說(shuō)出“Amazon.com 頁(yè)面”即可?。┐?URL 還將顯示出來(lái),并且應(yīng)該是“可刪節(jié)”的。也就是說(shuō),如果用戶(hù)刪去 URL 的末端,鍵入 http://yoursite.com/products,他們應(yīng)該看到所有產(chǎn)品的列表,或者至少應(yīng)該看到他們可以查看的所有類(lèi)別的產(chǎn)品列表。
注意:要獲得“可刪節(jié)”URL 的最好示例,可考慮使用由許多 blog 引擎生成的 URL。要查看 2004 年 1 月 28 日的帖子,用戶(hù)可以訪(fǎng)問(wèn)諸如 http://someblog.com/2004/01/28 的 URL。如果該 URL 被刪節(jié)為 http://someblog.com/2004/01,用戶(hù)將看到 2004 年 1 月的所有帖子。將該 URL 進(jìn)一步刪節(jié)為 http://someblog.com/2004 將顯示 2004 年的所有帖子。
除了簡(jiǎn)化 URL 之外,URL 重寫(xiě)還經(jīng)常用于處理網(wǎng)站重組,以免導(dǎo)致大量鏈接斷開(kāi)或書(shū)簽過(guò)期。
返回頁(yè)首
請(qǐng)求到達(dá) IIS 時(shí)將會(huì)發(fā)生什么情況
在正式研究 URL 如何實(shí)現(xiàn)重寫(xiě)之前,應(yīng)首先了解 Microsoft? Internet Information Services (IIS) 如何處理傳入請(qǐng)求,這一點(diǎn)非常重要。當(dāng)請(qǐng)求到達(dá) IIS Web 服務(wù)器時(shí),IIS 檢查被請(qǐng)求文件的擴(kuò)展名以確定如何處理該請(qǐng)求。IIS 可以自行處理請(qǐng)求(如 HTML 頁(yè)面、圖像以及其他靜態(tài)內(nèi)容),或者將請(qǐng)求路由到 ISAPI 擴(kuò)展。(ISAPI 擴(kuò)展是一個(gè)處理傳入 Web 請(qǐng)求的非托管編譯類(lèi)。其任務(wù)是生成被請(qǐng)求資源的內(nèi)容。)
例如,當(dāng)傳入針對(duì) Info.asp 網(wǎng)頁(yè)的請(qǐng)求時(shí),IIS 會(huì)將此消息路由到 asp.dll ISAPI 擴(kuò)展。然后,該 ISAPI 擴(kuò)展將加載被請(qǐng)求的 ASP 頁(yè)面,執(zhí)行該頁(yè)面,并將所呈現(xiàn)的 HTML 返回給 IIS,然后,IIS 將該 HTML 發(fā)送回請(qǐng)求客戶(hù)端。對(duì)于 ASP.NET 頁(yè)面,IIS 會(huì)將此消息路由到 aspnet_isapi.dll ISAPI 擴(kuò)展。然后,aspnet_isapi.dll ISAPI 擴(kuò)展將處理操作傳遞給托管的 ASP.NET 輔助進(jìn)程,該輔助程序?qū)⑻幚碚?qǐng)求,并返回 ASP.NET 網(wǎng)頁(yè)的呈現(xiàn) HTML。
您可以自定義 IIS,以指定擴(kuò)展名與 ISAPI 擴(kuò)展的映射關(guān)系。圖 1 顯示了 Internet Information Services 管理工具的“應(yīng)用程序配置”對(duì)話(huà)框。請(qǐng)注意,與 ASP.NET 有關(guān)的擴(kuò)展名(.aspx、ascx、config、asmx、rem、cs、vb 及其他)均已映射到 aspnet_isapi.dll ISAPI 擴(kuò)展。
圖 1. 已配置的文件擴(kuò)展名映射
討論 IIS 如何管理傳入請(qǐng)求稍稍超出了本文范圍。但是可以在 Michele Leroux Bustamante 的文章Inside IIS and ASP.NET 中找到對(duì)此內(nèi)容的深入討論。ASP.NET 引擎僅處理那些擴(kuò)展名已明確映射至 IIS 中的 aspnet_isapi.dll 的傳入 Web 請(qǐng)求,了解這一點(diǎn)非常重要。
使用 ISAPI 篩選器檢查請(qǐng)求
IIS 除了可以將傳入 Web 請(qǐng)求的文件擴(kuò)展名映射到相應(yīng)的 ISAPI 擴(kuò)展之外,還將執(zhí)行許多其他任務(wù)。例如,IIS 將嘗試對(duì)發(fā)出請(qǐng)求的用戶(hù)進(jìn)行身份驗(yàn)證,并確定通過(guò)身份驗(yàn)證的用戶(hù)是否有權(quán)限訪(fǎng)問(wèn)被請(qǐng)求的文件。在處理請(qǐng)求的有效期內(nèi),IIS 將經(jīng)歷幾個(gè)狀態(tài)。在每個(gè)狀態(tài)下,IIS 都將引發(fā)可以使用 ISAPI 篩選器以編程方式進(jìn)行處理的事件。
與 ISAPI 擴(kuò)展一樣,ISAPI 篩選器是在 Web 服務(wù)器上安裝的非托管代碼塊。ISAPI 擴(kuò)展被設(shè)計(jì)為可以響應(yīng)針對(duì)特定文件類(lèi)型的請(qǐng)求。另一方面,ISAPI 篩選器還包含可以對(duì) IIS 引發(fā)的事件進(jìn)行響應(yīng)的代碼。ISAPI 篩選器可以截取甚至修改傳入和傳出的數(shù)據(jù)。ISAPI 篩選器可以應(yīng)用于很多方面,包括:
?
身份驗(yàn)證和授權(quán)。
?
記錄和監(jiān)視。
?
HTTP 壓縮。
?
URL 重寫(xiě)。
雖然 ISAPI 篩選器可用于執(zhí)行 URL 重寫(xiě),但本文將討論如何使用 ASP.NET 實(shí)現(xiàn) URL 重寫(xiě)。不過(guò),我們將對(duì)使用 ISAPI 篩選器與使用 ASP.NET 中的技術(shù)實(shí)現(xiàn) URL 重寫(xiě)進(jìn)行權(quán)衡。
請(qǐng)求進(jìn)入 ASP.NET 引擎時(shí)將會(huì)發(fā)生什么情況
在 ASP.NET 之前,需要使用 ISAPI 篩選器來(lái)實(shí)現(xiàn) IIS Web 服務(wù)器上的 URL 重寫(xiě)。由于 ASP.NET 引擎與 IIS 非常相似,因此可以使用 ASP.NET 進(jìn)行 URL 重寫(xiě)。存在相似之處的原因在于 ASP.NET 引擎可以實(shí)現(xiàn)以下功能:
?
在處理請(qǐng)求時(shí)可以引發(fā)事件。
?
允許任意數(shù)量的 HTTP 模塊處理所引發(fā)的事件,這與 IIS 的 ISAPI 篩選器相似。
?
將呈現(xiàn)被請(qǐng)求資源這項(xiàng)任務(wù)委托給 HTTP 處理程序,該處理程序與 IIS 的 ISAPI 擴(kuò)展相似。
與 IIS 一樣,ASP.NET 引擎在請(qǐng)求的有效期內(nèi)將會(huì)觸發(fā)事件,通過(guò)發(fā)信號(hào)來(lái)表示其處理過(guò)程從一個(gè)狀態(tài)改變?yōu)榱肆硪粋€(gè)狀態(tài)。例如,當(dāng) ASP.NET 引擎首次響應(yīng)請(qǐng)求時(shí),BeginRequest 事件將被觸發(fā)。接下來(lái)觸發(fā)的是 AuthenticateRequest 事件,該事件在已建立用戶(hù)標(biāo)識(shí)時(shí)出現(xiàn)。(此外,還有大量的其他事件:AuthorizeRequest、ResolveRequestCache 和 EndRequest,等等。這些事件屬于 System.Web.HttpApplication 類(lèi);有關(guān)詳細(xì)信息,請(qǐng)參閱位于以下網(wǎng)址的技術(shù)文檔:HttpApplication Class Overview。)
正如上一部分所討論的,可以創(chuàng)建 ISAPI 篩選器以響應(yīng) IIS 引發(fā)的事件。同樣,ASP.NET 提供了 HTTP 模塊,該模塊可以響應(yīng)由 ASP.NET 引擎引發(fā)的事件。可以將 ASP.NET Web 應(yīng)用程序配置為具有多個(gè) HTTP 模塊。對(duì)于由 ASP.NET 引擎處理的每個(gè)請(qǐng)求,將初始化每個(gè)已配置的 HTTP 模塊,并允許將事件處理程序綁定到處理請(qǐng)求期間所引發(fā)的事件。請(qǐng)注意,對(duì)每個(gè)請(qǐng)求均使用了許多內(nèi)置 HTTP 模塊。其中的一個(gè)內(nèi)置 HTTP 模塊是 FormsAuthenticationModule,該模塊首先檢查是否使用了窗體身份驗(yàn)證,如果使用,將檢查是否對(duì)用戶(hù)進(jìn)行了身份驗(yàn)證。如果沒(méi)有使用,會(huì)自動(dòng)將用戶(hù)重定向到指定的登錄頁(yè)面。
如上所述,通過(guò)使用 IIS,傳入請(qǐng)求將最終發(fā)送給 ISAPI 擴(kuò)展,而 ISAPI 擴(kuò)展的任務(wù)是返回特定請(qǐng)求的數(shù)據(jù)。例如,在請(qǐng)求傳統(tǒng)的 ASP 網(wǎng)頁(yè)時(shí),IIS 將請(qǐng)求傳遞給 asp.dll ISAPI 擴(kuò)展,該擴(kuò)展的任務(wù)是返回被請(qǐng)求的 ASP 頁(yè)面的 HTML 標(biāo)記。ASP.NET 引擎使用相似的方法。初始化 HTTP 模塊后,ASP.NET 引擎的下一項(xiàng)任務(wù)是確定應(yīng)由哪個(gè) HTTP 處理程序來(lái)處理請(qǐng)求。
所有通過(guò) ASP.NET 引擎?zhèn)鬟f的請(qǐng)求最終都將到達(dá) HTTP 處理程序或 HTTP 處理程序工廠(chǎng)(HTTP 處理程序工廠(chǎng)僅返回 HTTP 處理程序的實(shí)例,然后使用該實(shí)例來(lái)處理請(qǐng)求)。最終的 HTTP 處理程序?qū)⒎祷仨憫?yīng),即呈現(xiàn)被請(qǐng)求的資源。此響應(yīng)將被發(fā)送回 IIS,然后 IIS 將響應(yīng)返回給提出請(qǐng)求的用戶(hù)。
ASP.NET 包括許多內(nèi)置的 HTTP 處理程序。例如,PageHandlerFactory 用于呈現(xiàn) ASP.NET 網(wǎng)頁(yè)。WebServiceHandlerFactory 用于呈現(xiàn) ASP.NET Web 服務(wù)的響應(yīng) SOAP 信封。TraceHandler 將向 trace.axd 呈現(xiàn)請(qǐng)求的 HTML 標(biāo)記。
圖 2 描述了如何處理對(duì) ASP.NET 資源的請(qǐng)求。首先,IIS 接收到請(qǐng)求,并將請(qǐng)求調(diào)度給 aspnet_isapi.dll。接下來(lái),ASP.NET 引擎對(duì)已配置的 HTTP 模塊進(jìn)行初始化。最后將調(diào)用正確的 HTTP 處理程序,并呈現(xiàn)被請(qǐng)求的資源,將所生成的標(biāo)記返回給 IIS 和請(qǐng)求客戶(hù)端。
圖 2. IIS 和 ASP.NET 正在處理請(qǐng)求
創(chuàng)建和注冊(cè)自定義 HTTP 模塊和 HTTP 處理程序
創(chuàng)建自定義 HTTP 模塊和 HTTP 處理程序是相對(duì)簡(jiǎn)單的任務(wù),包括創(chuàng)建實(shí)現(xiàn)正確接口的托管類(lèi)。HTTP 模塊必須實(shí)現(xiàn) System.Web.IHttpModule 接口,而 HTTP 處理程序和 HTTP 處理程序工廠(chǎng)必須分別實(shí)現(xiàn) System.Web.IHttpHandler 接口和 System.Web.IHttpHandlerFactory 接口。創(chuàng)建 HTTP 處理程序和 HTTP 模塊的細(xì)節(jié)超出了本文的范圍。要獲得詳細(xì)的背景知識(shí),請(qǐng)閱讀 Mansoor Ahmed Siddiqui 的文章HTTP Handlers and HTTP Modules in ASP.NET
創(chuàng)建了自定義 HTTP 模塊或 HTTP 處理程序之后,必須將其注冊(cè)到 Web 應(yīng)用程序。為整個(gè) Web 服務(wù)器注冊(cè) HTTP 模塊和 HTTP 處理程序僅需在 machine.config 文件中進(jìn)行簡(jiǎn)單的添加即可;而為特定 Web 應(yīng)用程序注冊(cè) HTTP 模塊或 HTTP 處理程序包括向應(yīng)用程序的 Web.config 文件中添加幾行 XML。
特別要說(shuō)明的是,要將 HTTP 模塊添加到 Web 應(yīng)用程序,應(yīng)在 Web.config 的 configuration/system.web 部分添加以下幾行:
<httpModules><add type="type" name="name" /></httpModules>
type 值提供了 HTTP 模塊的程序集和類(lèi)名稱(chēng),而 name 值提供了友好名稱(chēng),可以在 Global.asax 文件中使用此友好名稱(chēng)來(lái)引用 HTTP 模塊。
Web.config 的 configuration/system.web 部分中的 <httpHandlers> 標(biāo)記對(duì) HTTP 處理程序和 HTTP 處理程序工廠(chǎng)進(jìn)行了配置,如下所示:
<httpHandlers><add verb="verb" path="path" type="type" /></httpHandlers>
如上所述,對(duì)于每個(gè)傳入請(qǐng)求,ASP.NET 引擎將確定應(yīng)使用哪個(gè) HTTP 處理程序來(lái)呈現(xiàn)請(qǐng)求。此決定是基于傳入請(qǐng)求的動(dòng)詞和路徑做出的。動(dòng)詞將指定所作出的 HTTP 請(qǐng)求的類(lèi)型(GET 或 POST),而路徑將指定被請(qǐng)求文件的位置和文件名。因此,如果我們希望 HTTP 處理程序處理對(duì)擴(kuò)展名為 .scott 的文件的所有請(qǐng)求(GET 或 POST),可以在 Web.config 文件中添加下面幾行:
<httpHandlers><add verb="*" path="*.scott" type="type" /></httpHandlers>
其中,type 是 HTTP 處理程序的類(lèi)型。
注意:注冊(cè) HTTP 處理程序時(shí),應(yīng)確保 HTTP 處理程序使用的擴(kuò)展名已從 IIS 映射到 ASP.NET 引擎,這一點(diǎn)非常重要。也就是說(shuō),在本 .scott 示例中,如果 .scott 擴(kuò)展名沒(méi)有從 IIS 映射到 aspnet_isapi.dll ISAPI 擴(kuò)展,則對(duì)文件 foo.scott 的請(qǐng)求將導(dǎo)致 IIS 試圖返回文件 foo.scott 的內(nèi)容。為了使 HTTP 處理程序可以處理此請(qǐng)求,必須將 .scott 擴(kuò)展名映射到 ASP.NET 引擎。然后,ASP.NET 引擎將把請(qǐng)求正確地路由到相應(yīng)的 HTTP 處理程序。
有關(guān)注冊(cè) HTTP 模塊和 HTTP 處理程序的詳細(xì)信息,請(qǐng)務(wù)必參考<httpModules> element documentation<httpHandlers> element documentation。
返回頁(yè)首
實(shí)現(xiàn) URL 重寫(xiě)
可以使用 ISAPI 篩選器在 IIS Web 服務(wù)器級(jí)別實(shí)現(xiàn) URL 重寫(xiě),也可以使用 HTTP 模塊或 HTTP 處理程序在 ASP.NET 級(jí)別實(shí)現(xiàn) URL 重寫(xiě)。本文重點(diǎn)介紹如何使用 ASP.NET 實(shí)現(xiàn) URL 重寫(xiě),因此我們將不對(duì)使用 ISAPI 篩選器實(shí)現(xiàn) URL 重寫(xiě)的細(xì)節(jié)進(jìn)行深入探討。但是,有大量的第三方 ISAPI 篩選器可用于 URL 重寫(xiě),例如:
?
ISAPI Rewrite
?
IIS Rewrite
?
PageXChanger
?
還有許多其他的篩選器!
通過(guò) System.Web.HttpContext 類(lèi)的 RewritePath() 方法,可以在 ASP.NET 級(jí)別實(shí)現(xiàn) URL 重寫(xiě)。HttpContext 類(lèi)包含有關(guān)特定 HTTP 請(qǐng)求的 HTTP 特定信息。對(duì)于 ASP.NET 引擎收到的每個(gè)請(qǐng)求,均為該請(qǐng)求創(chuàng)建一個(gè) HttpContext 實(shí)例。此類(lèi)具有如下屬性:Request 和 Response,提供對(duì)傳入請(qǐng)求和傳出響應(yīng)的訪(fǎng)問(wèn);Application 和 Session,提供對(duì)應(yīng)用程序和會(huì)話(huà)變量的訪(fǎng)問(wèn);User,提供有關(guān)通過(guò)了身份驗(yàn)證的用戶(hù)的信息;其他相關(guān)屬性。
使用 Microsoft? .NET Framework Version 1.0,RewritePath() 方法可以接受單個(gè)字符串作為要使用的新路徑。HttpContext 類(lèi)的 RewritePath(string) 方法在內(nèi)部對(duì) Request 對(duì)象的 Path 屬性和 QueryString 屬性進(jìn)行更新。除了 RewritePath(string),.NET Framework 1.1 還包括另一種形式的 RewritePath() 方法,此方法可以接受三個(gè)字符串輸入?yún)?shù)。此備用重載形式不僅要設(shè)置 Request 對(duì)象的 Path 屬性和 QueryString 屬性,還要設(shè)置內(nèi)部成員變量,這些變量用于計(jì)算 Request 對(duì)象的 PhysicalPath、PathInfo 和 FilePath 屬性值。
要在 ASP.NET 中實(shí)現(xiàn) URL 重寫(xiě),需要?jiǎng)?chuàng)建 HTTP 模塊或 HTTP 處理程序,以便完成以下操作:
1.
檢查被請(qǐng)求的路徑,以確定 URL 是否需要重寫(xiě)。
2.
如果需要重寫(xiě),通過(guò)調(diào)用 RewritePath() 方法來(lái)重寫(xiě)路徑。
例如,假設(shè)我們的網(wǎng)站中包含每個(gè)員工通過(guò) /info/employee.aspx?empID=employeeID 均可訪(fǎng)問(wèn)的信息。為了使 URL 可以更多地被“刪節(jié)”,我們可以決定通過(guò)以下地址來(lái)訪(fǎng)問(wèn)員工頁(yè)面:/people/EmployeeName.aspx。這就是我們要使用 URL 重寫(xiě)的一個(gè)例子。也就是說(shuō),在請(qǐng)求 /people/ScottMitchell.aspx 頁(yè)面時(shí),我們要重寫(xiě)該 URL,以便使用 /info/employee.aspx?empID=1001 頁(yè)面。
使用 HTTP 模塊執(zhí)行 URL 重寫(xiě)
在 ASP.NET 級(jí)別執(zhí)行 URL 重寫(xiě)時(shí),可以使用 HTTP 模塊或 HTTP 處理程序來(lái)執(zhí)行重寫(xiě)。使用 HTTP 模塊時(shí),必須決定在請(qǐng)求有效期內(nèi)的哪個(gè)時(shí)間點(diǎn)上來(lái)檢查 URL 是否需要重寫(xiě)。乍一看,這似乎可以任意選擇,但決定會(huì)以一種明顯而微妙的方式對(duì)應(yīng)用程序產(chǎn)生影響。由于內(nèi)置 ASP.NET HTTP 模塊使用 Request 對(duì)象的屬性執(zhí)行任務(wù),因此選擇在何處執(zhí)行重寫(xiě)非常重要。(如上所述,重寫(xiě)路徑將改變 Request 對(duì)象的屬性值。)下面列出了這些密切相關(guān)的內(nèi)置 HTTP 模塊及其捆綁到的事件:
HTTP 模塊 事件 說(shuō)明
FormsAuthenticationModule
AuthenticateRequest
確定用戶(hù)是否通過(guò)了窗體身份驗(yàn)證。如果沒(méi)有,用戶(hù)將被自動(dòng)重定向到指定的登錄頁(yè)面。
FileAuthorizationMoudle
AuthorizeRequest
使用 Windows 身份驗(yàn)證時(shí),此 HTTP 模塊將檢查以確保 Microsoft? Windows? 帳戶(hù)對(duì)被請(qǐng)求的資源具有足夠的權(quán)限。
UrlAuthorizationModule
AuthorizeRequest
檢查以確保請(qǐng)求者可以訪(fǎng)問(wèn)指定的 URL。通過(guò) Web.config 文件中的 <authorization> 和 <location> 元素來(lái)指定 URL 授權(quán)。
如上所述,BeginRequest 事件在 AuthenticateRequest 之前觸發(fā),后者在 AuthenticateRequest 之前觸發(fā)。
可以執(zhí)行 URL 重寫(xiě)的一個(gè)安全位置是在 BeginRequest 事件中。也就是說(shuō),如果 URL 需要重寫(xiě),該操作將在任何一個(gè)內(nèi)置 HTTP 模塊運(yùn)行后執(zhí)行。使用窗體身份驗(yàn)證時(shí),這種方法存在一定的缺陷。如果您以前使用過(guò)窗體身份驗(yàn)證,您會(huì)了解當(dāng)用戶(hù)訪(fǎng)問(wèn)受限資源時(shí),他們將被自動(dòng)重定向到指定的登錄頁(yè)面。成功登錄后,用戶(hù)將被返回到他們第一次嘗試訪(fǎng)問(wèn)的頁(yè)面。
如果在 BeginRequest 或 AuthenticateRequest 事件中執(zhí)行 URL 重寫(xiě),登錄頁(yè)面(提交后)將把用戶(hù)重定向到重寫(xiě)后的頁(yè)面上。也就是說(shuō),假設(shè)用戶(hù)在其瀏覽窗口中鍵入了 /people/ScottMitchell.aspx,此地址將被重寫(xiě)為 /info/employee.aspx?empID=1001。如果將 Web 應(yīng)用程序配置為使用窗體身份驗(yàn)證,當(dāng)用戶(hù)第一次訪(fǎng)問(wèn) /people/ScottMitchell.aspx 時(shí),首先,URL 將被重寫(xiě)為 /info/employee.aspx?empID=1001;接下來(lái),F(xiàn)ormsAuthenticationModule 將運(yùn)行,并將用戶(hù)重定向到登錄頁(yè)面(如果需要)。但是,用戶(hù)在成功登錄后將被發(fā)送到 /info/employee.aspx?empID=1001,因?yàn)楫?dāng) FormsAuthenticationModule 運(yùn)行后,此 URL 即是請(qǐng)求的 URL。
同樣,在 BeginRequest 或 AuthenticateRequest 事件中執(zhí)行重寫(xiě)時(shí),UrlAuthorizationModule 看到的將是重寫(xiě)后的 URL。也就是說(shuō),如果您在 Web.config 文件中使用 <location> 元素來(lái)為特定的 URL 指定授權(quán),則必須引用重寫(xiě)后的 URL。
要解決這些細(xì)微問(wèn)題,您可以決定在 AuthorizeRequest 事件中執(zhí)行 URL 重寫(xiě)。此方法解決了 URL 授權(quán)和窗體身份驗(yàn)證的一些問(wèn)題,但同時(shí)也產(chǎn)生了新的問(wèn)題:文件授權(quán)無(wú)法工作。使用 Windows 身份驗(yàn)證時(shí),F(xiàn)ileAuthorizationModule 將檢查以確保通過(guò)身份驗(yàn)證的用戶(hù)具有訪(fǎng)問(wèn)特定 ASP.NET 頁(yè)面的相應(yīng)權(quán)限。
假設(shè)一組用戶(hù)對(duì) C:\Inetput\wwwroot\info\employee.aspx 沒(méi)有 Windows 級(jí)別的文件訪(fǎng)問(wèn)權(quán)限,并要嘗試訪(fǎng)問(wèn) /info/employee.aspx?empID=1001,他們將會(huì)收到授權(quán)錯(cuò)誤消息。但是,如果我們將 URL 重寫(xiě)移到 AuthenticateRequest 事件中,當(dāng) FileAuthorizationModule 檢查安全設(shè)置時(shí),仍然認(rèn)為被請(qǐng)求的文件是 people/ScottMitchell.aspx,因?yàn)樵?URL 必須被重寫(xiě)。因此,文件授權(quán)檢查將通過(guò),允許此用戶(hù)查看重寫(xiě)后的 URL /info/employee.aspx?empID=1001 的內(nèi)容。
那么,應(yīng)該何時(shí)在 HTTP 模塊中執(zhí)行 URL 重寫(xiě)?這取決于要使用的身份驗(yàn)證類(lèi)型。如果不想使用任何身份驗(yàn)證,則無(wú)論 URL 重寫(xiě)發(fā)生在 BeginRequest、AuthenticateRequest 還是 AuthorizeRequest 中都沒(méi)有什么關(guān)系。如果要使用窗體身份驗(yàn)證而不使用 Windows 身份驗(yàn)證,請(qǐng)將 URL 重寫(xiě)放在 AuthorizeRequest 事件處理程序中執(zhí)行。最后,如果要使用 Windows 身份驗(yàn)證,請(qǐng)?jiān)?BeginRequest 或 AuthenticateRequest 事件進(jìn)行過(guò)程中安排 URL 重寫(xiě)。
在 HTTP 處理程序中執(zhí)行 URL 重寫(xiě)
也可以由 HTTP 處理程序或 HTTP 處理程序工廠(chǎng)執(zhí)行 URL 重寫(xiě)。如上所述,HTTP 處理程序是負(fù)責(zé)生成特定類(lèi)型請(qǐng)求的內(nèi)容的類(lèi);HTTP 處理程序工廠(chǎng)是負(fù)責(zé)返回 HTTP 處理程序?qū)嵗念?lèi),該實(shí)例可以生成特定類(lèi)型請(qǐng)求的內(nèi)容。
在本文中,我們將對(duì)如何為 ASP.NET 網(wǎng)頁(yè)創(chuàng)建 URL 重寫(xiě) HTTP 處理程序工廠(chǎng)進(jìn)行討論。HTTP 處理程序工廠(chǎng)必須實(shí)現(xiàn) IHttpHandlerFactory 接口,此接口包括 GetHandler() 方法。初始化相應(yīng)的 HTTP 模塊后,ASP.NET 引擎將確定為給定的請(qǐng)求調(diào)用哪個(gè) HTTP 處理程序或 HTTP 處理程序工廠(chǎng)。如果要調(diào)用 HTTP 處理程序工廠(chǎng),ASP.NET 引擎將為 Web 請(qǐng)求調(diào)用傳入 HttpContext 的 HTTP 處理程序工廠(chǎng)的 GetHandler() 方法,以及一些其他信息。然后,HTTP 處理程序工廠(chǎng)必須返回一個(gè)對(duì)象,該對(duì)象將實(shí)現(xiàn)可以處理請(qǐng)求的 IHttpHandler。
要通過(guò) HTTP 程序程序執(zhí)行 URL 重寫(xiě),我們可以創(chuàng)建一個(gè) HTTP 處理程序工廠(chǎng),該處理程序工廠(chǎng)的 GetHandler() 方法將檢查被請(qǐng)求的路徑,以確定是否需要重寫(xiě) URL。如果需要,它可以調(diào)用傳入的 HttpContext 對(duì)象的 RewritePath() 方法,如前面所討論的。最后,HTTP 處理程序工廠(chǎng)可以返回由 System.Web.UI.PageParser 類(lèi)的 GetCompiledPageInstance() 方法返回的 HTTP 處理程序。(此技術(shù)與內(nèi)置 ASP.NET 網(wǎng)頁(yè) HTTP 處理程序工廠(chǎng) PageHandlerFactory 工作時(shí)所應(yīng)用的技術(shù)相同。)
由于所有 HTTP 模塊都將在實(shí)例化自定義 HTTP 處理程序工廠(chǎng)之前進(jìn)行初始化,因此,在將 URL 重寫(xiě)放在事件的后半段時(shí),使用 HTTP 處理程序工廠(chǎng)就會(huì)帶來(lái)相同的風(fēng)險(xiǎn),即文件授權(quán)無(wú)法工作。因此,如果您依賴(lài)于 Windows 身份驗(yàn)證和文件授權(quán),您可能希望為 URL 重寫(xiě)使用 HTTP 模塊方法。
在下一部分中,我們將對(duì)構(gòu)建可重用的 URL 重寫(xiě)引擎進(jìn)行討論。在介紹了 URL 重寫(xiě)引擎(可通過(guò)下載本文的代碼獲得)之后,我們將在剩下的兩個(gè)部分中對(duì) URL 重寫(xiě)的實(shí)際使用情況進(jìn)行介紹。首先,我們將討論如何使用 URL 重寫(xiě)引擎,并介紹一個(gè)簡(jiǎn)單的 URL 重寫(xiě)示例。接下來(lái),我們將利用重寫(xiě)引擎的正則表達(dá)式功能來(lái)提供真正“可刪節(jié)”的 URL。
返回頁(yè)首
構(gòu)建 URL 重寫(xiě)引擎
為了有助于描述如何在 ASP.NET Web 應(yīng)用程序中實(shí)現(xiàn) URL 重寫(xiě),我創(chuàng)建了 URL 重寫(xiě)引擎。此重寫(xiě)引擎將提供以下功能:
?
使用 URL 重寫(xiě)引擎的 ASP.NET 頁(yè)面開(kāi)發(fā)人員可以在 Web.config 文件中指定重寫(xiě)規(guī)則。
?
重寫(xiě)規(guī)則可以使用正則表達(dá)式來(lái)實(shí)現(xiàn)功能強(qiáng)大的重寫(xiě)規(guī)則。
?
可以輕松地將 URL 重寫(xiě)配置為使用 HTTP 模塊或 HTTP 處理程序。
在本文中,我們將介紹僅使用 HTTP 模塊的 URL 重寫(xiě)。要查看如何使用 HTTP 處理程序來(lái)執(zhí)行 URL 重寫(xiě),請(qǐng)參考可隨本文下載的代碼。
為 URL 重寫(xiě)引擎指定配置信息
讓我們先介紹一下 Web.config 文件中重寫(xiě)規(guī)則的結(jié)構(gòu)。首先,您需要在 Web.config 文件中指明要使用 HTTP 模塊還是 HTTP 處理程序來(lái)執(zhí)行 URL 重寫(xiě)。在下載代碼中,Web.config 文件包含兩個(gè)已注釋掉的條目:
<!--<httpModules><add type="URLRewriter.ModuleRewriter, URLRewriter"name="ModuleRewriter" /></httpModules>--><!--<httpHandlers><add verb="*" path="*.aspx"type="URLRewriter.RewriterFactoryHandler, URLRewriter" /></httpHandlers>-->
注釋掉 <httpModules> 條目,以使用 HTTP 模塊執(zhí)行重寫(xiě);注釋掉 <httpHandlers> 條目,以使用 HTTP 處理程序執(zhí)行重寫(xiě)。
除了指定使用 HTTP 模塊還是 HTTP 處理程序執(zhí)行重寫(xiě)外,Web.config 文件還包含重寫(xiě)規(guī)則:重寫(xiě)規(guī)則由兩個(gè)字符串組成:要在被請(qǐng)求的 URL 中查找的模式;要替換此模式的字符串(如果找到)。在 Web.config 文件中,此信息是使用以下語(yǔ)法表達(dá)的:
<RewriterConfig><Rules><RewriterRule><LookFor>要查找的模式</LookFor><SendTo>要用來(lái)替換模式的字符串</SendTo></RewriterRule><RewriterRule><LookFor>要查找的模式</LookFor><SendTo>要用來(lái)替換模式的字符串</SendTo></RewriterRule>...</Rules></RewriterConfig>
每個(gè)重寫(xiě)規(guī)則均由 <RewriterRule> 元素表達(dá)。要搜索的模式由 <LookFor> 元素指定,而要替換所找到的模式的字符串將在 <SentTo> 元素中輸入。這些重寫(xiě)規(guī)則將從頭到尾進(jìn)行計(jì)算。如果發(fā)現(xiàn)與某個(gè)規(guī)則匹配,URL 將被重寫(xiě),并且對(duì)重寫(xiě)規(guī)則的搜索將會(huì)終止。
在 <LookFor> 元素中指定模式時(shí),請(qǐng)注意,要使用正則表達(dá)式來(lái)執(zhí)行匹配和字符串替換。(稍后,我們將介紹一個(gè)真實(shí)的示例,說(shuō)明如何使用正則表達(dá)式來(lái)搜索模式。)由于模式是正則表達(dá)式,應(yīng)確保轉(zhuǎn)義正則表達(dá)式中的任何保留字符。(一些正則表達(dá)式保留字符包括:.、?、^、$ 及其他。可以通過(guò)在前面加反斜杠(如 \.)對(duì)這些字符進(jìn)行轉(zhuǎn)義,以匹配文字句點(diǎn)。)
使用 HTTP 模塊執(zhí)行 URL 重寫(xiě)
創(chuàng)建 HTTP 模塊與創(chuàng)建可以實(shí)現(xiàn) IHttpModule 接口的類(lèi)一樣簡(jiǎn)單。IHttpModule 接口定義了兩種方法:
?
Init(HttpApplication)。此方法在初始化 HTTP 模塊后觸發(fā)。在此方法中,您將把事件處理程序綁定到相應(yīng)的 HttpApplication 事件。
?
Dispose()。當(dāng)請(qǐng)求已完成并已發(fā)送回 IIS 時(shí)調(diào)用此方法。您應(yīng)當(dāng)在此處執(zhí)行所有最終的清除操作。
為了便于為 URL 重寫(xiě)創(chuàng)建 HTTP 模塊,我將從創(chuàng)建抽象基類(lèi) BaseModuleRewriter 開(kāi)始介紹。此類(lèi)將實(shí)現(xiàn) IHttpModule。在 Init() 事件中,它將 HttpApplication 的 AuthorizeRequest 事件綁定到 BaseModuleRewriter_AuthorizeRequest 方法。BaseModuleRewriter_AuthorizeRequest 方法將調(diào)用該類(lèi)傳入被請(qǐng)求的 Path 的 Rewrite() 方法,以及傳入 Init() 方法的 HttpApplication 對(duì)象。Rewrite() 方法是抽象的,也就是說(shuō),在 BaseModuleRewriter 類(lèi)中,Rewrite() 方法沒(méi)有方法主體;從 BaseModuleRewriter 派生而來(lái)的類(lèi)必須覆蓋此方法并提供方法主體。
具有此基類(lèi)后,只需創(chuàng)建由 BaseModuleRewriter 派生的類(lèi)即可,該類(lèi)可以覆蓋 Rewrite() 并在那里執(zhí)行 URL 重寫(xiě)邏輯。下面顯示了 BaseModuleRewriter 的代碼。
public abstract class BaseModuleRewriter : IHttpModule{public virtual void Init(HttpApplication app){// 警告!此代碼不適用于 Windows 身份驗(yàn)證!// 如果使用 Windows 身份驗(yàn)證,// 請(qǐng)改為 app.BeginRequestapp.AuthorizeRequest += newEventHandler(this.BaseModuleRewriter_AuthorizeRequest);}public virtual void Dispose() {}protected virtual void BaseModuleRewriter_AuthorizeRequest(object sender, EventArgs e){HttpApplication app = (HttpApplication) sender;Rewrite(app.Request.Path, app);}protected abstract void Rewrite(string requestedPath,HttpApplication app);}
請(qǐng)注意,BaseModuleRewriter 類(lèi)將在 AuthorizeRequest 事件中執(zhí)行 URL 重寫(xiě)。如上所述,如果將 Windows 身份驗(yàn)證與文件授權(quán)結(jié)合使用,您需要對(duì)此做出更改,以便可以在 BeginRequest 或 AuthenticateRequest 事件中執(zhí)行 URL 重寫(xiě)。
ModuleRewriter 類(lèi)擴(kuò)展了 BaseModuleRewriter 類(lèi),并負(fù)責(zé)執(zhí)行實(shí)際的 URL 重寫(xiě)。ModuleRewriter 包含單一覆蓋方法(Rewrite()),如下所示:
protected override void Rewrite(string requestedPath,System.Web.HttpApplication app){// 獲得配置規(guī)則RewriterRuleCollection rules =RewriterConfiguration.GetConfig().Rules;// 遍歷每個(gè)規(guī)則...for(int i = 0; i < rules.Count; i++){// 獲得要查找的模式,并且// 解析 Url(轉(zhuǎn)換為相應(yīng)的目錄)string lookFor = "^" +RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath,rules[i].LookFor) + "$";// 創(chuàng)建 regex(請(qǐng)注意,已設(shè)置 IgnoreCase...)Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);// 查看是否找到了匹配的規(guī)則if (re.IsMatch(requestedPath)){// 找到了匹配的規(guī)則 -- 進(jìn)行必要的替換string sendToUrl =RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath,re.Replace(requestedPath, rules[i].SendTo));// 重寫(xiě) URLRewriterUtils.RewriteUrl(app.Context, sendToUrl);break; // 退出 For 循環(huán)}}}
Rewrite() 方法從獲取 Web.config 文件中的一組重寫(xiě)規(guī)則開(kāi)始。然后,它將遍歷重寫(xiě)規(guī)則,每次遍歷一個(gè),對(duì)于每個(gè)規(guī)則,它將獲取規(guī)則的 LookFor 屬性,并使用正則表達(dá)式來(lái)確定是否在被請(qǐng)求的 URL 中找到了匹配的規(guī)則。
如果找到了匹配的規(guī)則,將在具有 SendTo 屬性值的被請(qǐng)求路徑上執(zhí)行正則表達(dá)式替換。然后,替換后的 URL 將被傳遞到 RewriterUtils.RewriteUrl() 方法中。RewriterUtils 是一個(gè) helper 類(lèi),此類(lèi)將提供一對(duì)由 URL 重寫(xiě) HTTP 模塊和 HTTP 處理程序使用的靜態(tài)方法。RewriterUrl() 方法僅調(diào)用 HttpContext 對(duì)象的 RewriteUrl() 方法。
注意:您可能已注意到,執(zhí)行正則表達(dá)式匹配和替換時(shí),將調(diào)用 RewriterUtils.ResolveUrl()。此 helper 方法只替換具有應(yīng)用程序路徑值的字符串中的所有 ~ 實(shí)例。
URL 重寫(xiě)引擎的整個(gè)代碼可隨本文下載。我們已經(jīng)介紹了大部分密切相關(guān)的組件,但還有一些其他組件(例如,對(duì) Web.config 文件中 XML 格式的重寫(xiě)規(guī)則進(jìn)行反序列化以使其成為對(duì)象的類(lèi)),以及用于 URL 重寫(xiě)的 HTTP 處理程序工廠(chǎng)。本文剩余的三個(gè)部分將對(duì) URL 重寫(xiě)的實(shí)際使用情況進(jìn)行介紹。
返回頁(yè)首
使用 URL 重寫(xiě)引擎執(zhí)行簡(jiǎn)單的 URL 重寫(xiě)
為了實(shí)際演示 URL 重寫(xiě)引擎,我們來(lái)構(gòu)建一個(gè)使用簡(jiǎn)單 URL 重寫(xiě)的 ASP.NET Web 應(yīng)用程序。假設(shè)我們所工作的公司通過(guò)網(wǎng)絡(luò)銷(xiāo)售分類(lèi)產(chǎn)品。這些產(chǎn)品分為以下幾個(gè)類(lèi)別:
類(lèi)別 ID 類(lèi)別名稱(chēng)
1
飲料
2
調(diào)味品
3
糖果
4
奶制品
...
...
假設(shè)我們已創(chuàng)建了名為 ListProductsByCategory.aspx 的 ASP.NET 網(wǎng)頁(yè),該網(wǎng)頁(yè)在查詢(xún)字符串中接受類(lèi)別 ID 值,并顯示屬于該類(lèi)的所有產(chǎn)品。因此,要查看我們銷(xiāo)售的飲料的用戶(hù)可以訪(fǎng)問(wèn) ListProductsByCategory.aspx?CategoryID=1,而那些要查看奶制品的用戶(hù)可以訪(fǎng)問(wèn) ListProductsByCategory.aspx?CategoryID=4。此外,還假設(shè)我們有一個(gè)名為 ListCategories.aspx 的頁(yè)面,該頁(yè)面列出了待售的所有產(chǎn)品類(lèi)別。
很顯然,這是一個(gè) URL 重寫(xiě)事例,因?yàn)樘峁┙o用戶(hù)的 URL 沒(méi)有為用戶(hù)帶來(lái)任何意義,也沒(méi)有為他們提供任何“可刪節(jié)性”。因此,讓我們使用 URL 重寫(xiě),以便在用戶(hù)訪(fǎng)問(wèn) /Products/Beverages.aspx 時(shí),他們的 URL 將被重寫(xiě)為 ListProductsByCategory.aspx?CategoryID=1。我們可以在 Web.config 文件中使用以下 URL 重寫(xiě)規(guī)則來(lái)實(shí)現(xiàn)此功能。
<RewriterConfig><Rules><!-- 產(chǎn)品制表者規(guī)則 --><RewriterRule><LookFor>~/Products/Beverages\.aspx</LookFor><SendTo>~/ListProductsByCategory.aspx?CategoryID=1</SendTo></RewriterRule><RewriterRule></Rules></RewriterConfig>
正如您可以看到的,此規(guī)則將進(jìn)行搜索,以查看用戶(hù)請(qǐng)求的路徑是否為 /Products/Beverages.aspx。如果是,它便將 URL 重寫(xiě)為 /ListProductsByCategory.aspx?CategoryID=1。
注意:請(qǐng)注意,<LookFor> 元素對(duì) Beverages.aspx 中的句點(diǎn)進(jìn)行了轉(zhuǎn)義。這是因?yàn)樵谡齽t表達(dá)式模式中使用了 <LookFor> 值,并且句點(diǎn)是正則表達(dá)式中的特殊字符,該字符表示“匹配任意字符”,例如,與 URL /Products/BeveragesQaspx 匹配。通過(guò)轉(zhuǎn)義句點(diǎn)(使用 \.),可以表明我們要匹配的是文字句點(diǎn),而不是任何舊的字符。
有了此規(guī)則之后,當(dāng)用戶(hù)訪(fǎng)問(wèn) /Products/Beverages.aspx 時(shí),頁(yè)面上將顯示待售的飲料。圖 3 顯示了訪(fǎng)問(wèn) /Products/Beverages.aspx 的瀏覽器的快照。請(qǐng)注意,在瀏覽器的地址欄中,URL 將讀取 /Products/Beverages.aspx,但用戶(hù)實(shí)際看到的是 ListProductsByCategory.aspx?CategoryID=1 的內(nèi)容。(實(shí)際上,Web 服務(wù)器上根本不存在 /Products/Beverages.aspx 文件?。?div style="height:15px;">
圖 3. 重寫(xiě) URL 之后請(qǐng)求類(lèi)別
與 /Products/Beverages.aspx 相似,下面我們要為其他產(chǎn)品類(lèi)別添加重寫(xiě)規(guī)則。此操作僅包括在 Web.config 文件的 <Rules> 元素內(nèi)添加附加的 <RewriterRule> 元素。請(qǐng)參閱下載內(nèi)容中的 Web.config 文件,以獲取用于此演示的一組完整的重寫(xiě)規(guī)則。
為了使 URL 更具可刪節(jié)性,最好使用戶(hù)只需從 /Products/Beverages.aspx 中刪除 Beverages.aspx 即可看到產(chǎn)品類(lèi)別的列表。乍一看,這可能是一項(xiàng)很普通的任務(wù)(只需添加一個(gè)將 /Products/ 映射到 /ListCategories.aspx 的重寫(xiě)規(guī)則即可)。但此操作存在一個(gè)微妙之處,即您必須首先創(chuàng)建一個(gè) /Products/ 目錄,并在 /Products/ 目錄中添加一個(gè)空的 Default.aspx 文件。
要理解需要執(zhí)行這些額外步驟的原因,可以參考前面的內(nèi)容,即 URL 重寫(xiě)引擎位于 ASP.NET 級(jí)別上。也就是說(shuō),如果 ASP.NET 引擎永遠(yuǎn)沒(méi)有機(jī)會(huì)處理請(qǐng)求,URL 重寫(xiě)引擎就沒(méi)有辦法檢測(cè)傳入的 URL。而且,請(qǐng)記住,僅當(dāng)被請(qǐng)求的文件具有相應(yīng)的擴(kuò)展名時(shí),IIS 才會(huì)將傳入請(qǐng)求傳遞給 ASP.NET 引擎。因此,如果用戶(hù)訪(fǎng)問(wèn) /Products/,而 IIS 沒(méi)有看到任何文件擴(kuò)展名,那么它將檢查目錄,以查看是否存在這樣一個(gè)文件,即該文件名為默認(rèn)文件名中的一個(gè)。(Default.aspx、Default.htm、Default.asp 等等。“IIS 管理”對(duì)話(huà)框中“Web 服務(wù)器屬性”對(duì)話(huà)框的“文檔”選項(xiàng)卡對(duì)這些默認(rèn)文件名進(jìn)行了定義。)當(dāng)然,如果 /Products/ 目錄不存在,IIS 將返回 HTTP 404 錯(cuò)誤。
因此,我們需要?jiǎng)?chuàng)建 /Products/ 目錄。另外,我們還需要在此目錄中創(chuàng)建一個(gè)文件 Default.aspx。這樣,當(dāng)用戶(hù)訪(fǎng)問(wèn) /Products/ 時(shí),IIS 將檢測(cè)目錄,查看是否存在一個(gè)名為 Default.aspx 的文件,然后將處理過(guò)程傳遞給 ASP.NET 引擎。然后,URL 重寫(xiě)器將在重寫(xiě) URL 時(shí)分解。
創(chuàng)建目錄和 Default.aspx 文件后,請(qǐng)繼續(xù)操作,并向 <Rules> 元素中添加以下重寫(xiě)規(guī)則:
<RewriterRule><LookFor>~/Products/Default\.aspx</LookFor><SendTo>~/ListCategories.aspx</SendTo></RewriterRule>
有了此規(guī)則之后,當(dāng)用戶(hù)訪(fǎng)問(wèn) /Products/ 或 /Products/Default.aspx 時(shí),他們將看到產(chǎn)品類(lèi)別列表,如圖 4 所示。
圖 4. 向 URL 添加“可刪節(jié)性”
處理回發(fā)
如果要重寫(xiě)的 URL 中包含一個(gè)服務(wù)器端的 Web 窗體并執(zhí)行回發(fā),則窗體回發(fā)后,將使用帶下劃線(xiàn)的 URL。也就是說(shuō),如果用戶(hù)在瀏覽器中輸入 /Products/Beverages.aspx,他們?cè)跒g覽器地址欄中看到的將是 /Products/Beverages.aspx,但是他們看到的內(nèi)容將是 ListProductsByCategory.aspx?CategoryID=1 的內(nèi)容。如果 ListProductsByCategory.aspx 執(zhí)行了回發(fā),用戶(hù)將被回發(fā)到 ListProductsByCategory.aspx?CategoryID=1,而不是 /Products/Beverages.aspx。這樣不會(huì)中斷任何內(nèi)容,但從用戶(hù)的角度考慮,如果單擊按鈕時(shí)突然看到 URL 更改會(huì)使他們感到不安。
出現(xiàn)這種情況的原因是:在呈現(xiàn) Web 窗體時(shí),它會(huì)將其操作屬性直接設(shè)置為 Request 對(duì)象中文件路徑的值。當(dāng)然,在呈現(xiàn) Web 窗體時(shí),URL 已從 /Products/Beverages.aspx 重寫(xiě)為 ListProductsByCategory.aspx?CategoryID=1,這表明 Request 對(duì)象報(bào)告用戶(hù)要訪(fǎng)問(wèn) ListProductsByCategory.aspx?CategoryID=1。只需使服務(wù)器端窗體不呈現(xiàn)操作屬性即可解決此問(wèn)題。(默認(rèn)情況下,如果窗體不包含操作屬性,瀏覽器將會(huì)回發(fā)。)
不幸的是,Web 窗體不允許您明確指定操作屬性,也不允許您設(shè)置某些屬性以禁用操作屬性的呈現(xiàn)。因此,我們必須自己來(lái)擴(kuò)展 System.Web.HtmlControls.HtmlForm 類(lèi),覆蓋 RenderAttribute() 方法并明確指出它不會(huì)呈現(xiàn)操作屬性。
由于繼承功能,我們可以獲得 HtmlForm 類(lèi)的所有功能,并且只需添加幾行代碼即可獲得所需的行為。以下顯示了自定義類(lèi)的完整代碼:
namespace ActionlessForm {public class Form : System.Web.UI.HtmlControls.HtmlForm{protected override void RenderAttributes(HtmlTextWriter writer){writer.WriteAttribute("name", this.Name);base.Attributes.Remove("name");writer.WriteAttribute("method", this.Method);base.Attributes.Remove("method");this.Attributes.Render(writer);base.Attributes.Remove("action");if (base.ID != null)writer.WriteAttribute("id", base.ClientID);}}}
已被覆蓋的 RenderAttributes() 方法的代碼僅包含 HtmlForm 類(lèi)的 RenderAttributes() 方法的準(zhǔn)確代碼,而不設(shè)置操作屬性。(我使用 Lutz Roeder 的Reflector 來(lái)查看 HtmlForm 類(lèi)的源代碼。)
創(chuàng)建此類(lèi)并對(duì)其進(jìn)行編譯之后,要在 ASP.NET Web 應(yīng)用程序中使用它,應(yīng)首先將其添加到 Web 應(yīng)用程序的 References 文件夾中。然后,要使用它來(lái)代替 HtmlForm 類(lèi),只需在 ASP.NET 網(wǎng)頁(yè)的頂部添加以下內(nèi)容即可:
<%@ Register TagPrefix="skm" Namespace="ActionlessForm"Assembly="ActionlessForm" %>
然后,將 <form runat="server">(如果有)替換為:
<skm:Form id="Form1" method="post" runat="server">
并將右邊的 </form> 標(biāo)記替換為:
</skm:Form>
您可以在 ListProductsByCategory.aspx(包含在本文的下載代碼中)中發(fā)現(xiàn)操作中的此自定義 Web Form 類(lèi)。下載內(nèi)容中還包含了用于無(wú)操作 Web Form 的 Visual Studio .NET 項(xiàng)目。
注意:如果要重寫(xiě)的目標(biāo) URL 沒(méi)有執(zhí)行回發(fā),則無(wú)需使用此自定義 Web Form 類(lèi)。
返回頁(yè)首
創(chuàng)建真正“可刪節(jié)”的 URL
前一部分中介紹的簡(jiǎn)單 URL 重寫(xiě)顯示了如何輕松地為 URL 重寫(xiě)引擎配置新的重寫(xiě)規(guī)則。但在使用正則表達(dá)式時(shí),重寫(xiě)規(guī)則的真正功能才會(huì)發(fā)揮更大作用,本部分將對(duì)此進(jìn)行探討。
Blog 在當(dāng)今正變得越來(lái)越流行,似乎每個(gè)人都擁有自己的 blog。如果您不熟悉 blog:blog 是經(jīng)常更新的個(gè)人頁(yè)面,通常作為聯(lián)機(jī)期刊。大多數(shù) blog 只記錄每天發(fā)生的事情,還有一些 blog 可能關(guān)注于特定的主題(例如,電影回顧、體育團(tuán)隊(duì)或計(jì)算機(jī)技術(shù))。
可以在任何地點(diǎn)對(duì) blog 進(jìn)行更新,更新頻率為從每天幾次到每周一次或兩次,具體情況取決于作者。通常,blog 主頁(yè)將顯示最近的 10 個(gè)條目,但實(shí)際上,所有 blog 軟件均提供存檔,訪(fǎng)問(wèn)者可以通過(guò)存檔讀取較早的帖子。Blog 是用于“可刪節(jié)”URL 的一個(gè)功能強(qiáng)大的應(yīng)用程序。假設(shè)在搜索 blog 的存檔時(shí),您在 URL /2004/02/14.aspx 上發(fā)現(xiàn)了您自己。如果您發(fā)現(xiàn)自己在閱讀 2004 年 2 月 14 日的帖子,您是否覺(jué)得很驚訝?而且,您可能希望查看 2004 年 2 月的所有帖子,在這種情況下,您可以嘗試將 URL 刪節(jié)為 /2004/02/。要查看 2004 年的所有帖子,您可以嘗試訪(fǎng)問(wèn) /2004/。
維護(hù) blog 時(shí),最好為訪(fǎng)問(wèn)者提供此級(jí)別的 URL“可刪節(jié)性”。許多 blog 引擎都提供此功能,但我們將討論如何使用 URL 重寫(xiě)來(lái)實(shí)現(xiàn)此功能。
首先,我們需要一個(gè) ASP.NET 網(wǎng)頁(yè),此頁(yè)面將按照日、月或年來(lái)顯示 blog 條目。假設(shè)我們有一個(gè) ShowBlogContent.aspx 頁(yè)面,該頁(yè)面的查詢(xún)字符串參數(shù)為年、月和日。要查看 2004 年 2 月 14 日的帖子,我們可以訪(fǎng)問(wèn) ShowBlogContent.aspx?year=2004&month=2&day=14。要查看 2004 年 2 月的所有帖子,我們可以訪(fǎng)問(wèn) ShowBlogContent.aspx?year=2004&month=2。最后,要查看 2004 年的所有帖子,我們可以瀏覽到 ShowBlogContent.aspx?year=2004。(可以在本文的下載內(nèi)容中找到 ShowBlogContent.aspx 的代碼。)
在這種情況下,如果用戶(hù)訪(fǎng)問(wèn) /2004/02/14.aspx,我們需要將 URL 重寫(xiě)為 ShowBlogContent.aspx?year=2004&month=2&day=14。所有三種情況(URL 指定了年、月和日時(shí);URL 僅指定了年和月時(shí);URL 僅指定了年時(shí))均可使用重寫(xiě)規(guī)則進(jìn)行處理:
<RewriterConfig><Rules><!-- Blog 內(nèi)容顯示程序規(guī)則 --><RewriterRule><LookFor>~/(\d{4})/(\d{2})/(\d{2})\.aspx</LookFor><SendTo>~/ShowBlogContent.aspx?year=$1&amp;month=$2&amp;day=$3</SendTo></RewriterRule><RewriterRule><LookFor>~/(\d{4})/(\d{2})/Default\.aspx</LookFor><SendTo><![CDATA[~/ShowBlogContent.aspx?year=$1&month=$2]]></SendTo></RewriterRule><RewriterRule><LookFor>~/(\d{4})/Default\.aspx</LookFor><SendTo>~/ShowBlogContent.aspx?year=$1</SendTo></RewriterRule></Rules></RewriterConfig>
這些重寫(xiě)規(guī)則表明了正則表達(dá)式的功能。在第一個(gè)規(guī)則中,我們使用模式 (\d{4})/(\d{2})/(\d{2})\.aspx 查找 URL。在簡(jiǎn)明英語(yǔ)中,它對(duì)應(yīng)了這樣一個(gè)字符串:首先是四個(gè)數(shù)字,后跟一個(gè)斜杠,然后是兩個(gè)數(shù)字,后跟一個(gè)斜杠,然后再跟兩個(gè)數(shù)字,最后是一個(gè) .aspx。每個(gè)數(shù)字組周?chē)睦ㄌ?hào)非常重要,通過(guò)它可以在相應(yīng)的 <SendTo> 屬性中引用這些括號(hào)內(nèi)的匹配字符。 特別是,我們可以針對(duì)第一、第二和第三個(gè)括號(hào)組分別使用 $1、$2 和 $3 引用回括號(hào)內(nèi)的匹配組。
注意:由于 Web.config 文件采用 XML 格式,但是必須對(duì)元素文字部分中的字符(如 &、< 和 >)進(jìn)行轉(zhuǎn)義。在第一個(gè)規(guī)則的 <SendTo> 元素中,& 被轉(zhuǎn)義為 &amp;。在第二個(gè)規(guī)則的 <SendTo> 中使用了另外一種技術(shù)(使用 <![CDATA[...]]> 元素),無(wú)需對(duì)內(nèi)部的內(nèi)容進(jìn)行轉(zhuǎn)義??梢允褂脙煞N方法中的任何一種,并且都會(huì)得到相同的結(jié)果。
圖 5、6 和 7 顯示了操作中的 URL 重寫(xiě)。數(shù)據(jù)實(shí)際上是從我的 bloghttp://scottonwriting.net/ 中拖過(guò)來(lái)的。圖 5 中顯示了 2003 年 11 月 7 日的帖子;圖 6 中顯示了 2003 年 11 月的所有帖子;圖 7 顯示了 2003 年的所有帖子。
圖 5. 2003 年 11 月 7 日的帖子
圖 6. 2003 年 11 月的所有帖子
圖 7. 2003 年的所有帖子
注意:URL 重寫(xiě)引擎在 <LookFor> 元素中需要使用正則表達(dá)式模式。如果您對(duì)正則表達(dá)式不熟悉,可以閱讀我在早些時(shí)候編寫(xiě)的一篇文章An Introduction to Regular Expressions。另外,還有一個(gè)很好的網(wǎng)站:RegExLib.com,在那里您可以獲取有關(guān)常用正則表達(dá)式的幫助信息,還可以共享您自己的自定義正則表達(dá)式。
構(gòu)建必備的目錄結(jié)構(gòu)
當(dāng)請(qǐng)求 /2004/03/19.aspx 時(shí),IIS 將通知 .aspx 擴(kuò)展,并將請(qǐng)求路由到 ASP.NET 引擎。請(qǐng)求在 ASP.NET 引擎的管道中移動(dòng)時(shí),URL 將被重寫(xiě)為 ShowBlogContent.aspx?year=2004&month=03&day=19,并且訪(fǎng)問(wèn)者會(huì)看到 2004 年 3 月 19 日的 blog 條目。但是當(dāng)用戶(hù)瀏覽到 /2004/03/ 時(shí)將會(huì)發(fā)生什么情況呢?除非有一個(gè) /2004/03/ 目錄,否則 IIS 將返回一個(gè) 404 錯(cuò)誤。此外,此目錄中還需要具有 Default.aspx 頁(yè)面,以便可以將請(qǐng)求傳遞給 ASP.NET 引擎。
因此,要使用這種方法,必須手動(dòng)創(chuàng)建一個(gè)用于每年的目錄(其中包含 blog 條目),并且目錄中具有一個(gè) Default.aspx 頁(yè)面。另外,在每年目錄中,您需要再手動(dòng)創(chuàng)建十二個(gè)目錄(01、02、?、?...、12),并且每個(gè)目錄中均有一個(gè) Default.aspx 文件。(如上所述,我們還必須執(zhí)行前面演示中的操作,即在 /Products/ 目錄中添加一個(gè) Default.aspx 文件,以便訪(fǎng)問(wèn) /Products/ 時(shí)可以正確顯示 ListCategories.aspx。)
很顯然,添加這樣一個(gè)目錄結(jié)構(gòu)可能是一件很痛苦的事情。解決此問(wèn)題的方法是使所有傳入的 IIS 請(qǐng)求都映射到 ASP.NET 引擎。通過(guò)這種方法,即使訪(fǎng)問(wèn) URL /2004/03/,IIS 也會(huì)如實(shí)地將請(qǐng)求傳遞給 ASP.NET 引擎(即使并不存在 /2004/03/ 目錄)。但是,使用這種方法將使 ASP.NET 引擎負(fù)責(zé)處理到達(dá) Web 服務(wù)器的所有類(lèi)型的傳入請(qǐng)求,包括圖像、CSS 文件、外部 JavaScript 文件、Macromedia Flash 文件,等等。
對(duì)處理所有文件類(lèi)型的全面討論遠(yuǎn)遠(yuǎn)超出了本文的范圍。有關(guān)使用此技術(shù)的 ASP.NET Web 應(yīng)用程序的示例,請(qǐng)參閱 .Text,一個(gè)開(kāi)放源 blog 引擎。.Text 可以配置為將所有請(qǐng)求均映射到 ASP.NET 引擎。它可以使用自定義 HTTP 處理程序來(lái)處理生成所有文件類(lèi)型的問(wèn)題,自定義 HTTP 處理程序了解如何生成典型的靜態(tài)文件類(lèi)型(圖像、CSS 文件,等等)。
返回頁(yè)首
結(jié)論
在本文中,我們討論了如何在 ASP.NET 級(jí)別通過(guò) HttpContext 類(lèi)的 RewriteUrl() 方法來(lái)執(zhí)行 URL 重寫(xiě)。正如我們所看到的,RewriteUrl() 更新了特定的 HttpContext‘s Request 屬性,從而更新了被請(qǐng)求的文件和路徑。最終結(jié)果是,從用戶(hù)角度來(lái)看,他們要訪(fǎng)問(wèn)某個(gè)特定的 URL,但從 Web 服務(wù)器端來(lái)看,被請(qǐng)求的卻是另一個(gè) URL。
可以在 HTTP 模塊或 HTTP 處理程序中重寫(xiě) URL。在本文中,我們介紹了如何使用 HTTP 模塊執(zhí)行重寫(xiě),并討論了在管道中的不同階段執(zhí)行重寫(xiě)的結(jié)果。
當(dāng)然,如果執(zhí)行 ASP.NET 級(jí)別的重寫(xiě),則僅當(dāng)已成功地將請(qǐng)求從 IIS 傳遞給 ASP.NET 引擎后才會(huì)發(fā)生 URL 重寫(xiě)。實(shí)際上,只有用戶(hù)請(qǐng)求帶 .aspx 擴(kuò)展名的頁(yè)面時(shí)才會(huì)出現(xiàn)這種情況。但是,如果您要使用戶(hù)可以進(jìn)入實(shí)際并不存在的 URL,但又希望重寫(xiě)到現(xiàn)有的 ASP.NET 頁(yè)面,則必須創(chuàng)建虛擬目錄和 Default.aspx 頁(yè)面,或者對(duì) IIS 進(jìn)行配置,以使所有傳入請(qǐng)求一律被路由到 ASP.NET 引擎。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Url Rewrite 再說(shuō)Url 重寫(xiě) (2)
Asp.net MVC項(xiàng)目的部署(二):對(duì)IIS7的補(bǔ)充
ASP.NET頁(yè)面與IIS底層交互和工作原理詳解
ASP.NET必須知道的:HttpModule,HttpHandler-程序開(kāi)發(fā)-紅黑聯(lián)盟
IIS6.0 基本原理
ASP.NET頁(yè)面剖析(1)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服