亚洲韩日午夜视频,欧美日韩在线精品一区二区三区,韩国超清无码一区二区三区,亚洲国产成人影院播放,久草新在线,在线看片AV色

您好,歡迎來到思海網(wǎng)絡(luò),我們將竭誠為您提供優(yōu)質(zhì)的服務(wù)! 誠征網(wǎng)絡(luò)推廣 | 網(wǎng)站備案 | 幫助中心 | 軟件下載 | 購買流程 | 付款方式 | 聯(lián)系我們 [ 會員登錄/注冊 ]
促銷推廣
客服中心
業(yè)務(wù)咨詢
有事點(diǎn)擊這里…  531199185
有事點(diǎn)擊這里…  61352289
點(diǎn)擊這里給我發(fā)消息  81721488
有事點(diǎn)擊這里…  376585780
有事點(diǎn)擊這里…  872642803
有事點(diǎn)擊這里…  459248018
有事點(diǎn)擊這里…  61352288
有事點(diǎn)擊這里…  380791050
技術(shù)支持
有事點(diǎn)擊這里…  714236853
有事點(diǎn)擊這里…  719304487
有事點(diǎn)擊這里…  1208894568
有事點(diǎn)擊這里…  61352289
在線客服
有事點(diǎn)擊這里…  531199185
有事點(diǎn)擊這里…  61352288
有事點(diǎn)擊這里…  983054746
有事點(diǎn)擊這里…  893984210
當(dāng)前位置:首頁 >> 技術(shù)文章 >> 文章瀏覽
技術(shù)文章

在ASP.NET中實(shí)現(xiàn)Url Rewriting

添加時間:2014-10-4 3:35:31  添加: 思海網(wǎng)絡(luò) 

分析如何使用微軟提供的ASP.NET來對動態(tài)產(chǎn)生的URL地址進(jìn)行網(wǎng)址重寫。 網(wǎng)址重寫是實(shí)現(xiàn)一種截取網(wǎng)址請求并將其進(jìn)行處理后重新指向到一個指定的網(wǎng)址的過程。作者本人在對各種實(shí)現(xiàn)網(wǎng)址重寫的技術(shù)進(jìn)行研究和探討后得出的經(jīng)驗(yàn)和方法,希望能對您有所幫助。 

  內(nèi)容簡介

  稍微花點(diǎn)時間看一看你做的網(wǎng)站里頭的URL地址,你看到類似這樣的地址嗎http://yoursite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&type=summary ?也許你會出于某種目的把大量的頁面文件從一個目錄甚至一個網(wǎng)站轉(zhuǎn)移到其他地方,而許多訪問者出于個人興趣或者研究目的之前就已經(jīng)將原有網(wǎng)址收藏了起來, 如果這時他從收藏夾打開該頁面的時候發(fā)現(xiàn)這已經(jīng)是壞鏈了。本文旨在介紹如何使用網(wǎng)址重寫將那些“難看”的網(wǎng)址轉(zhuǎn)換成比較有實(shí)際意義的網(wǎng)址,使其便于記憶。例如將http://yoursite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&type=summary轉(zhuǎn)換成如下地址:http://yoursite.com/ dispEmployeeInfo/459-099/summary.html 。我們甚至發(fā)現(xiàn) 網(wǎng)址重寫技術(shù)可以解決令人頭疼的404錯誤,或者說它可以創(chuàng)建一個智能化的404錯誤解決方案。

  如上所述,網(wǎng)址重寫是實(shí)現(xiàn)一種截取網(wǎng)址請求并將其進(jìn)行處理后重新指向到一個指定的網(wǎng)址的過程。 在網(wǎng)址重寫執(zhí)行的期間,相應(yīng)處理程序處理被請求的網(wǎng)址,從中提取出相關(guān)的值,然后重新指向一個新的指定地址。例如:由于一次網(wǎng)站目錄調(diào)整,原有的 /people/ 子目錄下的所有網(wǎng)頁全部移動到/info/employees/目錄,原訪問者從收藏夾或者其他什么地方點(diǎn)擊鏈接發(fā)出訪問/people/目錄下的文件的請求時,你肯定希望他還是能通過原有地址看到和原來相同的頁面,但實(shí)際上看到的卻是網(wǎng)址重寫指向的新目錄下的相應(yīng)文件。

  在老版本ASP中,使用網(wǎng)址重寫技術(shù)的途徑很少,要么寫一個 ISAPI過濾器,要么購買第三方廠商提供的網(wǎng)址重寫組件,然而在微軟提供的ASP.NET下你可以通過多種方法很簡單地開發(fā)出自己的網(wǎng)址重寫軟件,以滿足自己各種不同的需要。本文將和你一起討論這門針對ASP.NET開發(fā)人員的實(shí)現(xiàn)網(wǎng)址重寫的技術(shù),然后舉一些網(wǎng)址重寫實(shí)際應(yīng)用的例子。在我們深入探討網(wǎng)址重寫技術(shù)的細(xì)節(jié)之前,我們先看一下日常使用網(wǎng)址重寫技術(shù)實(shí)現(xiàn)的場景。

  網(wǎng)址重寫的一般用途

  創(chuàng)建一個數(shù)據(jù)操作的ASP.NET程序最常見的就是一個aspx頁面后面帶上一些查詢參數(shù)集合。例如在設(shè)計(jì)一個電子商務(wù)網(wǎng)站的時候,假定你設(shè)計(jì)了一項(xiàng)功能允許用戶瀏覽待售的商品,為了更加方便操作,你設(shè)計(jì)了一個頁面displayCategory.aspx將商品按照給定的分類顯示,那么該分類下的商品顯示頁面上應(yīng)該在頁面文件對應(yīng)網(wǎng)址后面加上了一個商品分類的查詢參數(shù),例如用戶要查詢待售的“裝飾品”,在數(shù)據(jù)庫中所有的裝飾品數(shù)據(jù)對應(yīng)的分類編號CategoryID的值為5,那么用戶會訪問如下網(wǎng)址:http://yoursite.com/displayCategory.aspx?CategoryID=5。

  創(chuàng)建一個包含類似這樣網(wǎng)址的網(wǎng)站最終有兩種結(jié)果,首先從最終用戶的角度來觀察,http://yoursite.com/displayCategory.aspx?CategoryID=5 這個網(wǎng)址有些雜亂, 可行性分析專家Jakob Neilson(主頁: http://useit.com/) 建議選擇網(wǎng)址顯示方式時候考慮如下要求(參考網(wǎng)址:http://www.useit.com/alertbox/990321.html):

  · 是否簡短

  · 是否易于輸入

  · 是否將站點(diǎn)結(jié)構(gòu)形象化

  · 是否具有隱蔽性,也就是讓用戶通過一個虛擬的看似有意義的導(dǎo)航地址訪問指向該地址

  我想還應(yīng)該在上述列表中再增加一條: 是否便于記憶。http://yoursite.com/displayCategory.aspx?CategoryID=5 這個地址沒有一個地方符合Neilson標(biāo)準(zhǔn)的任何一條,也不便于記憶。當(dāng)然,對于有經(jīng)驗(yàn)的網(wǎng)絡(luò)開發(fā)專家來說,他們很熟悉這種鍵值對構(gòu)成的查詢參數(shù)結(jié)構(gòu)體系,然而對于普通用戶來說輸入這些帶有參數(shù)的網(wǎng)址實(shí)在是太麻煩了。

  一種較好的方法就是使用一種比較直觀且容易記憶的方式來將網(wǎng)址表示為: http://yoursite.com/products/Widgets 乍一看很容易就會推斷這個網(wǎng)址所對應(yīng)的內(nèi)容極有可能會是顯示裝飾品(Widgets)信息,這個網(wǎng)址就變得更加容易記憶和傳播!然后我告訴我的同事:“請查看這個網(wǎng)址:http://yoursite.com/products/widgets ”不用我說第二遍,她可能一次就把地址敲到瀏覽器上了(你也可以在亞馬遜(Amazon.com)的網(wǎng)站上這樣嘗試一下)。很快就瀏覽器上就列出了裝飾品(Widgets)的內(nèi)容。這里“隱蔽性”表示:用戶可以自行變更網(wǎng)址的結(jié)尾,例如輸入:http://yoursite.com/products 就能看到全部分類相關(guān)的商品列表或者列出所有相關(guān)商品分類目錄列表。

  注:用上述簡單的變更網(wǎng)址內(nèi)容的方法來構(gòu)思一下如今的比較流行的Blog網(wǎng)站生成的網(wǎng)址。例如:要查詢2004年1月28日所發(fā)的帖子,只需輸入 http://someblog.com/2004/01/28 即可,如果將網(wǎng)址裁減為 http://someblog.com/2004/01 則顯示 2004年1月份的帖子 ,同樣將月份裁減掉得到 http://someblog.com/2004 則顯示出2004年全年所發(fā)的帖子。

  網(wǎng)址重寫技術(shù)除了用于將復(fù)雜的網(wǎng)址簡單化之外,它還能用于處理因網(wǎng)站目錄調(diào)整或者其他原因?qū)е庐a(chǎn)生大量的無效鏈接和過期書簽。 

  當(dāng)一個Web請求傳送到IIS會發(fā)生什么?

  在探討如何實(shí)現(xiàn)網(wǎng)址重寫這項(xiàng)技術(shù)之前,很有必要了解一下IIS是處理所接收的Web請求的機(jī)制。 當(dāng)一個Web請求到達(dá)IIS Web服務(wù)器時,IIS會根據(jù)所請求的文件后綴名來決定如何處理該請求,IIS可以處理諸如HTML頁面、圖片、靜態(tài)內(nèi)容,或者將請求轉(zhuǎn)發(fā)給ISAPI應(yīng)用程序,由該ISAPI應(yīng)用程序處理后生成HTML靜態(tài)內(nèi)容返回給IIS,最后由IIS將請求結(jié)果發(fā)送回給客戶端。(一個ISAPI應(yīng)用程序就是一套編譯好能隨時在后臺運(yùn)行的類庫,它的任務(wù)就是根據(jù)請求生成相關(guān)的內(nèi)容。)

  例如:如果IIS接收到一個對Info.asp的請求,它會將該請求轉(zhuǎn)交給 asp.dll來處理,該ISAPI應(yīng)用程序調(diào)出并執(zhí)行所請求的ASP頁面,然后把生成的HTML代碼返回給IIS,IIS最后把內(nèi)容發(fā)送回請求客戶端。對于ASP.NET頁面,IIS則將請求轉(zhuǎn)交給名為 aspnet_isapi.dll的ISAPI應(yīng)用程序來處理,該ISAPI應(yīng)用程序 調(diào)用托管的ASP.NET工作進(jìn)程來處理該請求,并將生成的HTML代碼返回給請求客戶端。

  你可以自定義IIS, 將某一類擴(kuò)展名映射到指定的ISAPI應(yīng)用程序,圖一顯示了IIS管理工具中的應(yīng)用程序配置對話框。


圖一.已配置的文件擴(kuò)展名映射

  關(guān)于對IIS如何管理所接收的請求的詳細(xì)探討有些超出本文內(nèi)容,,重要的是要了解 ASP.NET引擎只負(fù)責(zé)處理對擴(kuò)展名已經(jīng)被正確配置映射到aspnet_isapi.dll的網(wǎng)絡(luò)請求。

  用ISAPI過濾器來分析請求

  除了將請求的文件擴(kuò)展名映射到相應(yīng)的ISAPI應(yīng)用程序外,IIS還執(zhí)行一些其他工作。例如 IIS還主動對發(fā)出請求的客戶端用戶進(jìn)行授權(quán),并判斷已授權(quán)用戶是否對其請求的文件擁有訪問權(quán)限,在一個請求過程的全部生命期內(nèi),IIS的處理經(jīng)歷了幾個階段,在每一個階段IIS都生成一個事件,而該事件可以被ISAPI過濾器實(shí)時操控的。

  如同ISAPI應(yīng)用程序一樣, ISAPI過濾器也是一塊塊安裝在Web服務(wù)器上的非托管代碼。 ISAPI應(yīng)用程序用于對所接收的特定文件類型做出響應(yīng),而ISAPI過濾器含有對IIS生成的事件做出響應(yīng)的代碼(contain Code),甚至可以編輯進(jìn)出的數(shù)據(jù)。ISAPI也含有眾多應(yīng)用程序,包括:

  · 權(quán)限控制與授權(quán)(Authentication and Authorization)

  · 日志記錄與監(jiān)視(Logging and Monitoring)

  · HTTP內(nèi)容壓縮(HTTP Compression)

  · 網(wǎng)址重寫(URL Rewriting)

  本文所探討的用ASP.NET實(shí)現(xiàn)的網(wǎng)址重寫技術(shù)就是 基于ISAPI過濾器用于網(wǎng)址重寫的技術(shù)內(nèi)容,然而我們?nèi)匀灰懻撘幌戮烤故鞘褂肐SAPI過濾器還是使用ASP.NET應(yīng)用程序提供的技術(shù)來實(shí)現(xiàn)網(wǎng)址重寫技術(shù)。

  當(dāng)一個請求傳入ASP.NET引擎的時候會發(fā)生什么?

  ASP.NET問世之前,在IIS Web服務(wù)器上的網(wǎng)址重寫功能需要通過ISAPI過濾器來實(shí)現(xiàn),自從這個家伙問世后我們就能通過ASP.NET來實(shí)現(xiàn)URL重寫了,因?yàn)锳SP.NET的解釋引擎與IIS有極大的相似之處,產(chǎn)生這些相似性主要是因?yàn)?ASP.NET:

  · 在處理接收的請求的生命期內(nèi)也會產(chǎn)生事件;

  · 允許任意數(shù)量的HttpModule操控產(chǎn)生的事件,這與IIS中的ISAPI過濾器類似;

  · 將請求的資源委托給HttpHandler處理,這與IIS中的ISAPI應(yīng)用程序類似。

  和IIS一樣,在一個請求的整個生命期內(nèi),ASP.NET對該請求的處理狀態(tài)發(fā)出的狀態(tài)改變信號引發(fā)相應(yīng)的事件。例如:BeginRequest事件在ASP.NET開始響應(yīng)客戶端請求之始引發(fā);AuthenticateRequest事件在ASP.NET確立用戶身份后引發(fā),當(dāng)然還有諸如AuthorizeRequest,ResolveRequestCacheEndRequest等其它很多事件,這些 都是System.Web.HttpApplication類下的事件,更多信息請參考技術(shù)文檔中的類HttpApplication概要。

  如上所述, 可以創(chuàng)建ISAPI過濾器并用于相應(yīng)IIS引發(fā)的事件,同理,ASP.NET也提供了HttpModule用于響應(yīng)ASP.NET引擎引發(fā)的事件,一個ASP.NET應(yīng)用程序 通過配置可以擁有多個HttpModule。ASP.NET引擎 每處理一個請求,便初始化一個相應(yīng)配置好的HttpModule,并允許它 針對請求處理期間引發(fā)的事件生成相應(yīng)的事件委托。事實(shí)上ASP.NET引擎 處理每一個請求調(diào)用大量的事件委托。FormsAuthenticationModule就是眾多內(nèi)嵌HttpModule中的一個,它 首先檢查是否使用表單授權(quán),如果是的話,它 將檢查用戶是否已授權(quán),如果沒有授權(quán)則自動把用戶重定向到指定的登錄頁面。(即:在asp.net中可以直接記錄并判別用戶登錄授權(quán)的問題了!)

  回憶在IIS中,一項(xiàng)請求最后被轉(zhuǎn)交給一個ISAPI應(yīng)用程序處理,該應(yīng)用程序針對每一項(xiàng)請求進(jìn)行處理并返回相應(yīng)的數(shù)據(jù)。例如,客戶端發(fā)出一個訪問經(jīng)典ASP頁面的請求,IIS將該請求轉(zhuǎn)交給asp.dll程序處理,asp.dll針對該請求執(zhí)行asp頁面內(nèi)容,并返回HTML編碼。ASP.NET也使用了類似的手法,ASP.NET引擎在將這些HttpModule初始化后,判斷并決定調(diào)用相應(yīng)的HttpModule來處理該請求。(問:怎么程序操作httpModule)

  所有通過ASP.NET引擎解析的請求最終被送交一個HttpHandler或者HttpHandlerFactory(一個HttpHandler只是簡單地返回一個用于處理該請求的HttpHandler的實(shí)例。)最終的委托呈現(xiàn)并響應(yīng)所請求的HTML編碼,并發(fā)送回IIS,IIS則將HTML返回給請求客戶端。
ASP.NET包含許多HttpHandler,例如,PageHandlerFactory是用于呈現(xiàn)ASP.NET頁面內(nèi)容,WebServiceHandlerFactory用于呈現(xiàn)ASP.NET Web服務(wù)的SOAP數(shù)據(jù)包,TraceHandler用于將ASP.NET請求資源的HTML標(biāo)記寫入trace.axd。

  圖二描繪了一個針對ASP.NET資源的請求所經(jīng)過的處理流程。首先,IIS接收到該請求并將其轉(zhuǎn)交給aspnet_isapi.dll。其次,ASP.NET引擎將一些HttpModule初始化。最后,最終的HttpHandler被調(diào)用,生成相應(yīng)的標(biāo)記語言,并將其返回給IIS,最終返回到請求客戶端。


圖二.IIS和ASP.NET對請求的處理過程

  創(chuàng)建并注冊自定義HttpModule和HttpHandler

  創(chuàng)建自定義HttpModule的工作相對較簡單,它包括一個實(shí)現(xiàn)當(dāng)前接口的托管類,HttpModule必須實(shí)現(xiàn)System.Web.IHttpModule接口,同樣HttpHandlerHttpHandlerFactory必須分別實(shí)現(xiàn)System.Web.IHttpHandler接口和System.Web.IhttpHandlerFactory接口。有關(guān)創(chuàng)建HttpHandlerHttpModule的細(xì)節(jié)已經(jīng)超出本書范圍。

  一旦HttpModuleHttpHandler被創(chuàng)建后,必須向Web應(yīng)用程序注冊。如果要 向整個Web服務(wù)器HttpModuleHttpHandler只需簡單的寫入machine.config文件;如果是 由指定的Web應(yīng)用程序調(diào)用則需在該程序的web.config配置文件中添加幾行XML標(biāo)記。

  例如,要向指定的Web應(yīng)用程序注冊HttpModuleHttpHandler,只需向該Web應(yīng)程序的web.config配置文件中configuration\System.Web節(jié)中添加下列幾行:



<HttpModules>
 <add type="type" name="name" />
</HttpModules>

  其中type屬性為HttpModule的標(biāo)識號和類庫名稱,name屬性則為該模塊取一個較為友好的名稱方便 在Global.asax調(diào)用。
HttpHandlerHttpHandlerFactory則是 在web.config文件中configuration\System.Web節(jié)中添加<httpHandler>標(biāo)記,例如:

<httpHandlers>
 <add verb="verb" path="path" type="type" />
</HttpModules>

  回憶上文, ASP.NET對每一個接收到的請求指派相應(yīng)的HttpHandler來處理并呈現(xiàn)相應(yīng)內(nèi)容,該指派決定于所接收請求的verb和path的內(nèi)容,verb為HTTP請求的類型:GET或者POST,path則為請求的文件的路徑和文件名。如果我們打算用一個HttpHandler來處理所有GET類型和POST類型的并且文件擴(kuò)展名為.scott的內(nèi)容,可以在web.config相應(yīng)配置節(jié)中加入下列標(biāo)記:

<httpHandlers>
 <add varb="*" path=".scott" type="type" />
</httpHandlers>

  其中 type是我們定義的HttpHandler的類型。

  注意:在注冊HttpHandler的時候必須注意HttpHandler所使用的文件擴(kuò)展名必須已經(jīng)在IIS中做指向ASP.NET引擎的映射,在上面.scott擴(kuò)展名的例子中,如果我們所使用的.scott擴(kuò)展名如果沒有在IIS中做指向ASP.NET引擎的映射的話,假定對foo.scott文件發(fā)出請求,該請求 將導(dǎo)致IIS將foo.scott文件內(nèi)容直接呈現(xiàn)給客戶端,為了能夠讓HttpHandler處理該請求,必須將.scott擴(kuò)展名在IIS中做指向ASP.NET引擎的映射,之后IIS才能正確地將.scott的請求轉(zhuǎn)交給相應(yīng)的HttpHandler。

  實(shí)現(xiàn)網(wǎng)址重寫

  網(wǎng)址重寫技術(shù)不但可以在IIS Web服務(wù)器一級通過ISAPI過濾器實(shí)現(xiàn),而且還可以在ASP.NET一級通過HttpModule或者HttpHandler實(shí)現(xiàn)。本文主要關(guān)注在ASP.NET一級實(shí)現(xiàn)網(wǎng)址重寫技術(shù),所以此時不必關(guān)注在ISAPI應(yīng)用程序中實(shí)現(xiàn)網(wǎng)址重寫的技術(shù)細(xì)節(jié),而且有很多第三方廠商提供的ISAPI過濾器。

  構(gòu)建網(wǎng)址重寫引擎

  在ASP.NET中實(shí)現(xiàn)網(wǎng)址重寫很簡單, 只需調(diào)用System.Web.HttpContext類的RewritePath()方法即可。HttpContext類中包含有關(guān)于特定HTTP請求的HTTP規(guī)范信息。ASP.NET引擎每接收到一個特定請求后便針對該請求創(chuàng)建一個特定的實(shí)例,這個類包含一些屬性諸如: RequestResponse屬性,分別提供對請求和響應(yīng)的訪問;ApplicationSession屬性提供對Application變量和Session變量的訪問;User屬性提供對已授權(quán)用戶信息的訪問。

  在微軟.NET Framework 1.0版本中,RewritePath()方法接收一個新路徑的簡單字符串,在其內(nèi)部HttpContext類的RewritePath(string)方法內(nèi)在地更新Request對象的路徑和查詢參數(shù)。除了RewritePath(string)方法之外,.NET Framework 1.1版還提供了另外一些重載版本,其中一個重載版本接收三個輸入字符串參數(shù),這種交替的重載形式不僅僅只是設(shè)置Request對象的路徑和查詢參數(shù)這些屬性,而是設(shè)置更深層的成員變量,這些成員變量用于為PhysicalPath、PathInfoFilePath屬性計(jì)算Request對象值。

  為了實(shí)現(xiàn)ASP.NET中的網(wǎng)址重寫,我們需要創(chuàng)建一個HttpHandlerHttpModule用于:

  ·根據(jù)請求的路徑?jīng)Q定所需要重寫的路徑;

  ·重寫路徑,如果需要的話可以調(diào)用RewritePath方法;

  以前文所構(gòu)建的那個站點(diǎn)為例,可以通過/info/employee.aspx?empID=EmployeeID來訪問每一個雇員的信息。為了使這個網(wǎng)址更加地具有“隱蔽性”,我們可能會使用更加容易理解的訪問方式如:/people/雇員名.aspx。這里就有了一個網(wǎng)址重寫的案例:當(dāng)接收到對/people/ScottMitchell.aspx的請求的時候,我們就得使用網(wǎng)址重寫使得對該頁面的請求被重寫指向到先前使用的/info/employee?EmpID=1001地址。

  使用HttpModule來調(diào)用網(wǎng)址重寫

  在ASP.NET一級來執(zhí)行網(wǎng)址重寫,既可以使用HttpHandler,也可以使用HttpModule。當(dāng)使用HttpModule的時候,必須決定如果該網(wǎng)址需要被重寫的話,究竟應(yīng)該在整個請求的生命周期期間的那一個點(diǎn)來使用。乍一看著有些武斷,但是這個決定以重大而且微妙的方式影響到你的應(yīng)用程序。之所以作出對網(wǎng)址重寫點(diǎn)的選擇是因?yàn)閮?nèi)嵌的ASP.NET HttpModule使用Request對象的屬性值來完成自己的工作(回憶一下重寫路徑對Request對象的屬性值的改變),這些內(nèi)嵌HttpModule和相應(yīng)事件的密切關(guān)系列舉如下:

HttpModule 事件 簡介
FormsAuthenticationModule AuthenticateRequest 判斷用戶是否已通過表單授權(quán)方式獲取授權(quán),如果沒有的話則將用戶重定向到指定的登錄頁面
FileAuthorizationModule AuthorizeRequest 當(dāng)使用Windows授權(quán)方式的時候,該HttpModule判斷并確定該Microsoft Windows帳戶是否對其請求的資源擁有足夠的權(quán)限
UrlAuthorizationModule AuthorizeRequest 檢查并確認(rèn)請求者是否對所訪問的網(wǎng)址擁有權(quán)限。該Url授權(quán)可以在web.config文件的<authorization>和<location>元素中配置

  回想一下BeginRequest事件在AuthenticateRequest事件之前引發(fā),而AuthenticateRequest事件又在AuthorizeRequest事件之前引發(fā)。

  實(shí)現(xiàn)網(wǎng)址重寫的一個較為安全的場合就是把它放在在BeginRequest事件中執(zhí)行,這意味著如果要執(zhí)行網(wǎng)址重寫的話,在眾多內(nèi)嵌HttpModule運(yùn)行的時候他已經(jīng)完成了。這種途徑的最終用途淋漓盡致地體現(xiàn)在表單驗(yàn)證上。當(dāng)用戶訪問受限資源的時候, 如果之前使用了表單驗(yàn)證,他會自動被重定向到指定的登錄頁面,在成功登錄之后,用戶被重定向回先前試圖訪問的受限制頁面。

  如果把網(wǎng)址重寫放在BeginRequest事件或者AuthenticateRequest事件中,在登錄頁面上執(zhí)行提交后,該頁面會將用戶重定向到網(wǎng)址重寫指定的頁面。假定當(dāng)用戶在瀏覽器上敲入/people/ScottMitchell.aspx地址,該地址是要被重定向到/info/employee.aspx?EmpID=1001的, 如果該Web應(yīng)用程序設(shè)定使用表單驗(yàn)證,當(dāng)用戶開始訪問/people/ScottMitchell.aspx的時候,該網(wǎng)址將重寫指向/info/employee.aspx?EmpID=1001,接著ForumAuthenticationModule啟動,如果需要的話將用戶重定向到登錄頁面,用戶登錄后重定向到的頁面將是/info/employee.aspx?EmpID=1001,這也是自從FormAuthenticationModule啟動運(yùn)行時所發(fā)出請求的頁面。
同上類似,當(dāng)把網(wǎng)址重寫放在BeginRequest事件或者AuthenticateRequest事件中運(yùn)行的時候,UrlAuthenticationModule也發(fā)現(xiàn)了網(wǎng)址重寫指向的網(wǎng)址,這意味著如果在該應(yīng)用程序的web.config文件中<location>節(jié)為特定的網(wǎng)址配置特定的授權(quán)地址的話,你得引用重寫所指向的網(wǎng)址。

  為了解決這個微妙的問題,一個可能就是把網(wǎng)址重寫放在AuthorizeRequest事件中運(yùn)行,但是在使用這種方法解決URL授權(quán)和表單授權(quán)的異常時又引入了一個新的缺陷:文件授權(quán)會失效。當(dāng)使用Windows驗(yàn)證的時候,FileAuthorizationModule檢查并驗(yàn)證已通過驗(yàn)證的用戶是否擁有足夠的權(quán)限訪問特定的ASP.NET頁面。

  假定有一群用戶并沒有Windows級別的訪問權(quán)限訪問C:\inetpub\wwwroot\info\employee.aspx,當(dāng)這些用戶試圖訪問/info/employee.aspx?EmpID=1001的時候,他們會得到未授權(quán)的錯誤,如果我們把網(wǎng)址重寫放到AuthenticateRequest事件中運(yùn)行,當(dāng)FileAuthorizationModule驗(yàn)證該安全性設(shè)置的時候,他仍任人為被請求的文件是/people/ScottMitchell.aspx,而這時該網(wǎng)址已經(jīng)被重寫了,因此FileAuthorizationModule會直接放行,讓用戶看到了網(wǎng)址重寫指向的內(nèi)容:/info/employee.aspx?Empid=1001。

  那么什么時候在HttpModule調(diào)用網(wǎng)址重寫合適呢?他決定于所使用的驗(yàn)證方式,當(dāng)然如果不使用驗(yàn)證方式的話,那么無論是在BeginRequest事件、AuthenticateRequest事件還是AuthorizeRequest事件中調(diào)用網(wǎng)址重寫沒有多大區(qū)別,如果使用表單驗(yàn)證方式并且不使用Windows驗(yàn)證方式的話,把網(wǎng)址重寫放入AuthorizeRequest事件委托中調(diào)用既可,如果使用Windows驗(yàn)證方式的話,把這項(xiàng)功能放入BeginRequest事件或者AuthenticateRequest事件調(diào)用就行了。

  使用HttpHandler來調(diào)用網(wǎng)址重寫

  除了上面所述方法外,網(wǎng)址重寫也可以放入HttpHandler或者HttpHandlerFactory中調(diào)用。HttpHandler是一個負(fù)責(zé)針對特定請求生成相應(yīng)內(nèi)容的類,而HttpHandlerFactory返回一個HTTP的實(shí)例,該實(shí)例針對特定請求生成相應(yīng)內(nèi)容。

  本節(jié)將著眼于為這些ASP.NET頁面創(chuàng)建一個網(wǎng)址重寫的HttpHandlerFactory。創(chuàng)建HttpHandlerFactory必須實(shí)現(xiàn)IHTTPHandlerFactory接口,它包括一個GetHandler()方法。ASP.NET引擎在初始化這些HttpModule后做出決定針對該請求調(diào)用相應(yīng)的HttpHandler或者HttpHandlerFactory,在調(diào)用HttpHandlerFactory的時候,針對該Web請求以及隨同的其他信息的HttpContext中經(jīng)過的的HttpHandlerFactoryGetHandler()方法將被ASP.NET引擎調(diào)用,HttpHandlerFactory必須返回一個能委托該請求的對象,并且該對象要能實(shí)現(xiàn)IHttpHandler接口。

  要通過一個HttpHandler來調(diào)用網(wǎng)址重寫,可以先創(chuàng)建一個HttpHandlerFactory,它的GetHandler()方法檢查所請求的網(wǎng)址并決定是否需要調(diào)用網(wǎng)址重寫。如果要調(diào)用網(wǎng)址重寫的話則調(diào)用前文所述的已通過檢查的HttpContext對象的RewritePath()方法。最后該HttpHandlerFactory返回一個由類System.Web.UI.PageParserGetCompiledInstance()方法返回的HttpHandler。(這與內(nèi)嵌于ASP.NET頁面的HttpHandlerFactoryPageHandlerFactory)的工作原理相同。)

  在所有HttpModule被初始化后,HttpHandlerFactory就開始被實(shí)例化。把網(wǎng)址重寫放在這些事件場所的最后一個里頭調(diào)用的時候,也會碰到相同的問題:文件授權(quán)將會失效。如果非要依賴于Windows驗(yàn)證和文件驗(yàn)證的時候,你可能得使用HttpModule來調(diào)用網(wǎng)址重寫了。
下一章我們著眼于如何構(gòu)建一個可重用的網(wǎng)址重寫引擎,使用下文所提的這些示例均以真實(shí)案例作為參照,在作者主頁上提供下載。先用用一個簡單的網(wǎng)址重寫的例子來探討如何實(shí)現(xiàn)網(wǎng)址重寫,緊接著將利用網(wǎng)址重寫引擎中正則表達(dá)式的強(qiáng)大處理能力來展示真正“隱蔽”的網(wǎng)址重寫技術(shù)!

  使用網(wǎng)址重寫引擎實(shí)現(xiàn)簡單的網(wǎng)址重寫

  為了便于在Web應(yīng)用程序中實(shí)現(xiàn)網(wǎng)址重寫,我構(gòu)建了一個網(wǎng)址重寫引擎,該引擎提供下列功能:

  ·可以在web.config文件中為頁面開發(fā)者定義其所使用的網(wǎng)址重寫引擎的規(guī)則;

  ·通過使用正則表達(dá)式來使所制定的網(wǎng)址重寫規(guī)則具有更加強(qiáng)大的重寫能力;

  ·能夠通過簡單配置即可在HttpModuleHttpHandler中使用網(wǎng)址重寫。

  本節(jié)只探討通過HttpModule來實(shí)現(xiàn)網(wǎng)址重寫,要了解如何通過HttpHandler來實(shí)現(xiàn)網(wǎng)址重寫請下載本文提供的代碼。

  1. 設(shè)置網(wǎng)址重寫引擎的配置信息

  我們來探討一下在web.config中網(wǎng)址重寫規(guī)則的配置節(jié)。首先必須在web.config文件中指出是否需要在HttpHandler或者HttpModule中調(diào)用網(wǎng)址重寫,在web.config中,下文已經(jīng)包含了兩個已經(jīng)被注釋掉的配置節(jié):

 <!-- 
<HttpModules>
 <add type="URLRewriter.ModuleRewriter,URLRewriter" name="ModuleRewriter"/>
</HttpModules>
 -->

 <!-- 
<httpHandlers>
 <add verb="*" path="*.aspx" type="URLRewriter.RewriterFactoryHandler,URLRewriter" />
</httpHandlers>
 -->

  被注釋掉的<HttpModules>為配置使用HttpModule調(diào)用網(wǎng)址重寫;注釋掉的<httpHandler>為配置使用HttpHandler調(diào)用網(wǎng)址重寫。
不論配置使用<HttpModules>還是<httpHandlers>調(diào)用網(wǎng)址重寫,除此之外還須配置網(wǎng)址重寫規(guī)則,一條重寫規(guī)則包括兩項(xiàng)字符串:請求URL中的查找模式和針對該模式的匹配成功后的替換字符串。該信息在web.config文件中用下列標(biāo)簽描述:

<RewriterConfig>
 <Rules>
 <RewriterRule>
 <LookFor>pattern to look for</LookFor>
 <SendTo>String to replace pattern with </SendTo>
 </RewriterRule>
 <RewriterRule>
 <LookFor>pattern to look for</LookFor>
 <SendTo>String to replace pattern with </SendTo>
 </RewriterRule>
 
 </Rules>
</RewriterConfig>

  每一條規(guī)則都用一個<RewriterRule>元素表示,以<LookFor>節(jié)表示查詢模式,當(dāng)查詢模式發(fā)現(xiàn)匹配字符串時便用<SendTo>節(jié)表示的字符串進(jìn)行替換。這些規(guī)則從上到下進(jìn)行查詢匹配,如果找到一個匹配則按此規(guī)則執(zhí)行網(wǎng)址重寫,并且停止查找。

  配置<LookFor>節(jié)要使用正則表達(dá)式來進(jìn)行字符串匹配和替換。(在此我們舉一個例子來說明如何使用正則表達(dá)式來對字符串進(jìn)行匹配和替換。)既然該查找模式是一個正則表達(dá)式,那么要注意避開對正則表達(dá)式保留字符串的直接使用。(正則表達(dá)式的保留字符串包括有:.,?,^,$,等等,可以通過在前面加上一個反斜線來引用這些保留字符,例如\.表示引用一個句點(diǎn))

  2. 使用HttpModule來執(zhí)行網(wǎng)址重寫

  創(chuàng)建一個HttpModule很簡單,只要創(chuàng)建一個實(shí)現(xiàn)IHttpModule接口的類,該IHttpModule接口定義了兩個方法:

  ·Init(HttpApplication),該方法在HttpModule初始化時引發(fā),通過該方法為HttpApplication事件調(diào)用相應(yīng)的事件委托;

  ·Dispose(),當(dāng)相應(yīng)請求處理結(jié)束并發(fā)送回IIS調(diào)用此方法,通過此方法執(zhí)行最終所有的清理和回收程序。

  為了更加方便地為網(wǎng)址重寫創(chuàng)建HttpModule,從一開始我就創(chuàng)建一個抽象的基類(BaseModuleRewriter),該類實(shí)現(xiàn)了IHttpModule接口。在Init(HttpApplication)事件中,它通過BaseModuleRewriter_AuthorizeRequest方法引發(fā)了HttpApplicationAuthorizeRequest事件,該BaseModuleRewriter_AuthorizeRequest方法通過該類的Rewrite()方法重寫傳入?yún)?shù)HttpApplication對象的內(nèi)部請求虛擬路徑(Path)。在BaseModuleRewriter對象中,該Rewrite()方法是抽象的,并且沒有實(shí)際內(nèi)容,但在繼承自該類的對象中必須重載Rewrite()方法并為該方法提供實(shí)際內(nèi)容。

  通過對該基類的繼承,所有需要做的工作就是創(chuàng)建一個繼承自BaseModuleRewriter的類,重載Rewrite()方法并在該方法中添加網(wǎng)址重寫邏輯代碼。下文列出BaseModuleRewriter代碼:

public abstract class BaseModuleRewriter : IHttpModule
  {
 public virtual void Init(HttpApplication app)  {
 // WARNING! This does not work with Windows authentication!
 // If you are using Windows authentication, 
 // change to app.BeginRequest 
 app.AuthorizeRequest += new EventHandler(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);
}

  注意:該BaseModuleRewriter類將網(wǎng)址重寫放在AuthorizeRequest事件中調(diào)用,如果要使用Windows驗(yàn)證并使用文件驗(yàn)證模式時請修改代碼將網(wǎng)址授權(quán)放在BeginRequest或者AuthenticateRequest事件中。

  ModuleRewriter繼承自BaseModuleRewriter,并真正意義地實(shí)現(xiàn)了網(wǎng)址重寫的操作,該類僅包含一個重載了的方法Rewrite(),其內(nèi)容如下文所示:

protected override void Rewrite(string requestedPath, System.Web.HttpApplication app)
  {
 // get the configuration rules 
 RewriterRuleCollection rules = RewriterConfiguration.GetConfig().Rules;
 // iterate through each rule 
 for(int i = 0; i < rules.Count; i++)
  {
 // get the pattern to look for, and 
 // Resolve the Url (convert ~ into the appropriate directory) 
 string lookFor = "^" + 
 RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, rules[i].LookFor) + "$";
 // Create a regex (note that IgnoreCase is set
 Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);
 // See if a match is found 
 if (re.IsMatch(requestedPath))
  {
 // match found - do any replacement needed 
 string sendToUrl = RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, re.Replace(requestedPath, rules[i].SendTo));
 // Rewrite the URL 
 RewriterUtils.RewriteUrl(app.Context, sendToUrl);
 break; // exit the for loop 
 }
 }
}

  該Rewriter()方法以獲取web.config文件中的網(wǎng)址重寫規(guī)則的設(shè)置為起始,它通過循環(huán)訪問各條網(wǎng)址重寫規(guī)則,每次均獲取當(dāng)前規(guī)則中的LookFor屬性,用正則表達(dá)式驗(yàn)證并判斷是否查找是否對當(dāng)前請求的網(wǎng)址是否有匹配。

  如果發(fā)現(xiàn)一條匹配,將用當(dāng)前規(guī)則的SendTo值對請求的路徑執(zhí)行一個正則表達(dá)式替換,替換后的地址通過參數(shù)的形式傳給RewriterUtils.RewriteUrl()方法,RewriterUtils是一個幫助類,它提供一對HttpModuleHttpHandler都可以使用的靜態(tài)方法,RewriterUrl()方法只是簡單地調(diào)用了HttpContext對象的RewritePath()方法。

  注意:你已經(jīng)注意到了當(dāng)執(zhí)行正則表達(dá)式匹配和替換的時候調(diào)用了一個RewriterUtils.ResolveUrl()方法。該幫助方法簡單地替換了應(yīng)用程序路徑中“~”的所有實(shí)例。

  我們已經(jīng)探討了主要的部分,但是還有其它一些組件諸如將web.config文件中XML格式化了的網(wǎng)址重寫規(guī)則反序列化至一個對象的類定義、通過HttpHandlerFactory實(shí)現(xiàn)網(wǎng)址重寫的類定義等。本文最后三節(jié)將通過一些真實(shí)案例來探討網(wǎng)址重寫的技術(shù)。

  3. 用網(wǎng)址重寫引擎實(shí)現(xiàn)簡單的網(wǎng)址重寫

  為了更好地示范網(wǎng)址重寫引擎的運(yùn)行,我們來建立一個ASP.NET Web應(yīng)用程序來實(shí)現(xiàn)簡單的網(wǎng)址重寫引擎。假定我們?yōu)橐患以诰銷售各類商品的公司服務(wù),這些產(chǎn)品劃分為以下類別:

  分類編號(CategoryID) 分類名稱(CategoryName)
   1          飲料(Beverages)
   2          調(diào)味品(Condiments)
   3          工藝品(Confections)
   4          日記本(Diary Products)
   ... ...
  
  假定已經(jīng)建立好一個名為ListProductsByCategoryID.aspx的ASP.NET頁面文件,它通過查詢參數(shù)獲取一個分類編號,并根據(jù)此編號獲取所有該分類下的所有商品。如果用戶想瀏覽所銷售的飲料類商品可以通過ListProductsByCategoryID.aspx?CategoryID=1來訪問,如果用戶想瀏覽所銷售的日記本類商品可以通過ListProductsByCategoryID.aspx?CategoryID=4來訪問。假定還有一個頁面ListCategories.aspx,它列出所有代售商品的分類編號。

  顯然這里發(fā)現(xiàn)了一個網(wǎng)址重寫的案例。對于用戶來說他們所輸入的地址不具有任何實(shí)際意義并且不具備任何“隱蔽性”,倒不如使用網(wǎng)址重寫引擎讓用戶去訪問/Products/Baverage.aspx地址,系統(tǒng)將該地址重寫到ListProductsByCategoryID.aspx?CategoryID=1。我們可以在web.config文件中來完成網(wǎng)址重寫任務(wù):

<RewriterConfig>
 <Rules>
 <! —- Rules for products lister -->
 <RewriterRule>
 <LookFor>~/Products/Baverage.aspx</LookFor>
 <SendTo>~/ListProductsByCategoryID.aspx?CategoryID=1</SendTo>
 </RewriterRule>
 </Rules>
</RewriterConfig>

  很明顯地看到,搜索用戶訪問的路徑是否匹配/Products/Baverage.aspx,如果匹配的話,則將網(wǎng)址重寫到/ListProductsByCategoryID.aspx?CategoryID=1。

  注意:你會發(fā)現(xiàn)<LookFor>節(jié)點(diǎn)中避免直接在“Baverage.aspx”中使用句點(diǎn)“.”是因?yàn)椋糒ookFor>節(jié)點(diǎn)的值是正則表達(dá)式的匹配模式,在正則表達(dá)式中句點(diǎn)符號是一個特殊字符,它表示匹配任何一個字符,也就是說如果訪問BaverageQaspx時也會發(fā)生匹配,為了避免發(fā)生這個句點(diǎn)引起的匹配我們得在該句點(diǎn)符號前面加上一個“\”,表示引用句點(diǎn)符號。

  通過該規(guī)則定義,當(dāng)用戶訪問/Products/Baverage.aspx文件的時候,他們將看到代售的飲料類商品列表信息。圖3為訪問/Products/Baverage.aspx地址時的瀏覽器截圖,注意在瀏覽器中地址欄上顯示的是用戶輸入的/Products/Baverage.aspx地址,但是實(shí)際訪問的地址卻是網(wǎng)址重寫后的/ListProductsByCategoryID.aspx?CategoryID=1。(事實(shí)上,在服務(wù)器上根本就不存在/Products/Baverage.aspx文件。


圖三.網(wǎng)址重寫后的對商品分類的請求

  和/Products/Baverage.aspx類似,下一步我們添加其它分類的重寫規(guī)則,只需簡單地在web.config文件中<Rules>中在添加其他<RewriteRule>節(jié)即可。該演示完整的重寫規(guī)則集合請參考下載文檔的web.config文件中的定義。

  為了讓該網(wǎng)址更具有“隱蔽性”,如果讓用戶把/Products/Baverage.aspx后面Baverage.aspx一段截去,在瀏覽器中輸入/Products/來瀏覽產(chǎn)品分類列表會更好一些。乍一看,這項(xiàng)任務(wù)微不足道,只需添加一條網(wǎng)址重寫規(guī)則將/Products/映射到/ListCategories.aspx即可。然而這里有一個微妙之處,你必須先創(chuàng)建一個/Products/目錄,并在里面放一個空文件Default.aspx。

  要認(rèn)識為什么這些額外的步驟是必須的,先回顧一下前文。網(wǎng)址重寫引擎是處于ASP.NET一級的,也就是說,如果ASP.NET沒有獲得處理請求的機(jī)會的話,網(wǎng)址重寫引擎就不能對輸入的網(wǎng)址請求作出判斷。此外,IIS僅在請求文件包含相應(yīng)擴(kuò)展名時才將請求轉(zhuǎn)交給ASP.NET引擎。如果用戶訪問/Products/,IIS并不知道其擴(kuò)展名是什么,于是它檢查該目錄下的文件看是否包含有默認(rèn)首頁文件名(Default.aspx,Default.htm,Default.asp,等等,這些文件名在IIS管理工具對話框中Web服務(wù)器屬性對話框中的文檔標(biāo)簽中定義。)當(dāng)然,如果/Products/目錄不存在的話,IIS將返回一個HTTP 404錯誤。

  所以我們需要創(chuàng)建一個/Products/目錄并在該目錄下額外創(chuàng)建一個空文件Default.aspx,IIS會檢查該目錄下的文件,發(fā)現(xiàn)有一個默認(rèn)文件名Default.aspx,于是將請求轉(zhuǎn)交給ASP.NET,這樣,網(wǎng)址重寫引擎才能生效。

<RewriterRule>
 <LookFor>~/Products/Default.aspx</LookFor>
 <SendTo>~ListCategories.aspx</SendTo>
</RewriterRule>

  通過該規(guī)則,用戶訪問/Products/Default.aspx或者訪問/Products/都可以看到如圖四所示的產(chǎn)品分類列表。


圖四.在網(wǎng)址上添加“隱蔽性”

  4.處理回送數(shù)據(jù)

  如果要重寫的網(wǎng)址上包含有服務(wù)器端Web Form并執(zhí)行數(shù)據(jù)回送,當(dāng)該Web Form回送數(shù)據(jù)時會暴露出真實(shí)的網(wǎng)址,也就是說,當(dāng)用戶訪問/Products/Baverage.aspx時,瀏覽器上地址欄顯示的也是/Products/Baverage.aspx,但是實(shí)際上是訪問/ListProdutsByCategoryID.aspx?CategoryID=1的內(nèi)容,如果ListProductsByCategoryID.aspx頁面執(zhí)行了數(shù)據(jù)回送的話,用戶被數(shù)據(jù)回送定向給原始的/ListProductByCategoryID.aspx?CategoryID=1頁面上,而不是/Products/Baverage.aspx頁面。這雖然不是什么大問題,但是用戶會覺察到點(diǎn)擊一個按鈕時網(wǎng)址發(fā)生了的變化,這也許會令人不安,因?yàn)槿绻鲇诰W(wǎng)址安全的角度來說,直接把真實(shí)的網(wǎng)址暴露出來了。
之所以發(fā)生這種現(xiàn)象的原因是當(dāng)Web Form在呈現(xiàn)之時就明確地設(shè)置其action屬性為當(dāng)前Request對象中文件路徑的值。當(dāng)然,在Web Form呈現(xiàn)之時,從/Produts/Baverage.aspx到/ListProductsByCategoryID.aspx?CategoryID=1的網(wǎng)址重寫就已經(jīng)執(zhí)行完畢了,這意味著Request對象所匯報(bào)的是當(dāng)前用戶所訪問的地址是/ListProductsByCategoryID.aspx?CategoryID=1。這么看來,只需讓該服務(wù)器端表單在呈現(xiàn)之時不呈現(xiàn)action屬性即可解決問題了。(對瀏覽器來說,如果不設(shè)置action屬性的話,那么在提交的時候?qū)⑹褂闷淠J(rèn)值。)

  然而不幸的是該Web Form不會允許你指定action屬性,也不會允許你通過設(shè)置一些屬性來達(dá)到禁用呈現(xiàn)action屬性的目的。得自行繼承System.Web.HtmlControls.HtmlForm這個類,并重載該類的RenderAttribute()方法,明確指出該類不呈現(xiàn)acton屬性。

  感謝繼承這個強(qiáng)大的功能,使得我們很簡單就獲取了HtmlForm這個類下所有的功能定義,只需少量幾行代碼就達(dá)到所需目的,完整代碼如下所示:

namespace ActionlessForm
  {
 public class Form:System.Web.UI.HtmlControls.HtmlForm
  {
 protected override void RenderAttributes(System.Web.UI.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",this.ClientID);
 }
 }
 }
}

  對RenderAttributes()方法重載的代碼包含了原類HtmlFormRenderAttributes()方法全部的代碼內(nèi)容,只是簡單地去掉了設(shè)置action屬性這一節(jié)。

  當(dāng)創(chuàng)建并編譯了這個類后,將其添加到引用目錄即可在該ASP.NET Web應(yīng)用程序中使用。為了將原有HtmlForm類替換,只需簡單地在頁面頂部添加下列代碼:

 <%  @ Register TagPrefix = " skm " Namespace = " ActionlessForm " Assembly = " ActionlessForm " %>

  然后將<Form runat=”server”>標(biāo)簽替換為

<skm:Form id="Form1" method="post" runat="Server">

  并將結(jié)束標(biāo)記</Form>替換為

<skm:Form>

  你可以查看該文檔相關(guān)下載中的ListProductsByCategoryID.aspx文件中的自定義Web Form,該下載已經(jīng)提供了完整的Visual Studio.NET項(xiàng)目文件包。

  注意:如果你打算進(jìn)行網(wǎng)址重寫的地址不執(zhí)行數(shù)據(jù)回送,則沒有必要使用該自定義Web Form的類。

  創(chuàng)建真正“隱蔽”的網(wǎng)址

  上一節(jié)簡單網(wǎng)址重寫的示例展示了如何通過新的網(wǎng)址重寫規(guī)則來輕松地配置網(wǎng)址重寫引擎,本節(jié)將通過出眾的正則表達(dá)式來展示網(wǎng)址重寫的強(qiáng)大威力。

  時下正在流行Blog,很多人都擁有一個自己的Blog。不論你是否對Blog感到陌生,他們正在不斷地更新自己的Blog頁面,這些頁面就像一個個人日記本一樣。大多數(shù)Bloger只是簡單地記錄每天發(fā)生的事情,也有一些聚焦于某一主題,比如影評、球迷組織、電腦技術(shù)等。

  Blog可以在任何地點(diǎn)由作者進(jìn)行更新,更新次數(shù)可以是一天多次,也可以是一周一兩次。在Blog頁面上只顯示最近10條更新,但事實(shí)上所有的Blog軟件都提供了存檔記錄,訪客可以閱讀其歷史記錄。有了“隱蔽”的網(wǎng)址,Blog應(yīng)用程序?qū)⒆兊酶訌?qiáng)大。假定你通過/2004/02/14.aspx來查詢自己的Blog上的文章,你會為閱讀到2004年2月14日的Blog感到驚訝嗎?此外你可能為了訪問2004年2月所有的Blog而將該地址裁減為/2004/02/,要訪問2004年所有的Blog,你可能會試著去訪問/2004/。

  在維護(hù)一個Blog的時候,如果將這種具有“隱蔽性”的網(wǎng)址提供給用戶將會更好。實(shí)際上很多Blog引擎都提供了這種網(wǎng)址重寫的功能,現(xiàn)在來看看這些是如何通過網(wǎng)址重寫實(shí)現(xiàn)的。

  首先,我們需要一個頁面能夠分別按照年、月、日分別顯示Blog的內(nèi)容。假定現(xiàn)在已經(jīng)做好了一個頁面文件ShowBlogContent.aspx,它能分別獲取年、月、日的查詢參數(shù),要查看2004年2月14日所發(fā)的帖子,我們可以訪問/ShowBlogContent.aspx?year=2004&month=2&day=14,要瀏覽2004年2月的數(shù)據(jù)可以訪問/ShowBlogContent.aspx?year=2004&month=2,要查詢2004年所有數(shù)據(jù)可以訪問/ShowBlogContent.aspx?year=2004。(在下載文件中提供ShowBlogContent.aspx源代碼。)

  然后,當(dāng)用戶訪問/2004/02/14.aspx時,我們需要將他訪問的網(wǎng)址重寫到/ShowBlogContent.aspx?year=2004&month=2&day=14上。這里需要制定三條網(wǎng)址重寫規(guī)則:當(dāng)指定訪問年月日時、當(dāng)指定訪問年月時和當(dāng)指定訪問年時。

<RewriterConfig>
 <Rules>
 <!-- Rules for Blog Content Displayer -->
 <RewriterRule>
 <LookFor>~/(d{4})/(d{2})/(d{2}).aspx</LookFor>
 <SendTo>~/ShowBlogContent.aspx?year=$1&month=$2&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>

  這些網(wǎng)址重寫規(guī)則展示了正則表達(dá)式的強(qiáng)大威力。第一條規(guī)則按照(\d{4})/(\d{2})/(\d{2})\.aspx模式進(jìn)行查找,通俗的說,它查找是否包含匹配xxxx/xx/xx.aspx格式的字符串,其中x表示數(shù)字,每一組數(shù)字必須用圓括號括起來,這樣可以在相應(yīng)<SendTo>節(jié)內(nèi)引用圓括號內(nèi)的匹配字符串。我們可以使用$1、$2、$3來分別引用前面匹配的圓括號組,其中$1,$2,$3分別表示所匹配的第一、第二、第三個圓括號組。

  注意:由于web.config是XML格式的文檔,所以在文本域內(nèi)必須回避直接使用一些特殊字符,如:&,<和>符號等。在第一條網(wǎng)址重寫規(guī)則的<SendTo>節(jié)中用&來表示引用&符號,在第二條網(wǎng)址重寫規(guī)則的<SendTo>節(jié)中用<![CDATA[...]]>元素來表示其中所有的內(nèi)容都是文本域,不再需要用轉(zhuǎn)義字符來表示引用。這兩種方法都可以實(shí)現(xiàn)同樣的目的。


  注意:要使用網(wǎng)址重寫引擎,強(qiáng)烈推薦在<LookFor>節(jié)中使用正則表達(dá)式。

  創(chuàng)建必須的目錄結(jié)構(gòu)

  當(dāng)IIS接收到對/2004/03/19.aspx的請求時,他發(fā)現(xiàn)文件擴(kuò)展名.aspx,便將該請求轉(zhuǎn)交給ASP.NET引擎處理,在ASP.NET 引擎中傳遞時,該地址被重寫到/ShowBlogContent.aspx?year=2004&month=3&day=19,最后用戶將看到該Blog上2004年3月19日所有的帖子,但是在用戶訪問/2004/03/時會發(fā)生什么呢?除非已經(jīng)存在一個/2004/01/的目錄,否則IIS將返回一個404錯誤,而且該目錄下還必須要有一個默認(rèn)頁面Default.aspx,IIS才能將請求轉(zhuǎn)交給ASP.NET引擎處理。

  通過這種方法你得手動為每一年的Blog創(chuàng)建一個年份的目錄并在該年份下放置一個默認(rèn)文件Default.aspx,而且還得在該年份目錄下創(chuàng)建每一月的目錄,從01、02、...、12,每一個目錄下也要防止一個默認(rèn)文件Default.aspx。(回想前面的例子,為了將/Products/重寫到/ListCategories.aspx也是要建立一個/Products/目錄并放置一個默認(rèn)Default.aspx文件。

  很明顯,這樣創(chuàng)建目錄結(jié)構(gòu)的過程是很痛苦的。解決這種問題的一個辦法就是設(shè)置IIS將所有接收的請求都轉(zhuǎn)交給ASP.NET引擎來處理,這種方法,甚至連訪問這種地址/2004/04/,IIS都如實(shí)地將其轉(zhuǎn)交給ASP.NET引擎處理,這種方法造成ASP.NET引擎得處理所有傳入的請求,包括css文件,圖片文件、Java文件以及Flash文件等等。

  關(guān)于對所有類型文件的處理的詳細(xì)討論已經(jīng)超出了本書范圍。有關(guān)在ASP.NET Web應(yīng)用程序中使用這些技術(shù)的例子請?jiān)L問.Text 這個開源的Blog。.Text 可以通過配置將所有請求都轉(zhuǎn)交給ASP.NET處理。它使用了一個自定義的HttpHandler來處理所有類型的文件類型,這個自定義的HttpHandler可以識別并判斷如何處理所有的文件類型。(圖像文件、CSS文件等等。)

  結(jié)束語

  本文探討了通過類HttpContext類的RewriteUrl()方法來實(shí)現(xiàn)ASP.NET一級的網(wǎng)址重寫,正如我們所看到那樣,RewriteUrl()方法在修改這個特有的HttpContextRequest的屬性時也修改了所請求的文件和路徑。實(shí)際得到的效果就是在用戶訪問其特有的網(wǎng)址的時候,他實(shí)際卻是在服務(wù)器端請求另一個與此不同的網(wǎng)址。

  網(wǎng)址重寫不但可以在HttpModule中執(zhí)行,也可以在HttpHandler中運(yùn)行。本文我們探討了在一個HttpModule中執(zhí)行網(wǎng)址重寫,也研究了一下網(wǎng)址重寫在ASP.NET中的各個不同場所的情況。

  當(dāng)然,在ASP.NET一級的網(wǎng)址重寫中,只有在IIS成功地將請求轉(zhuǎn)交給ASP.NET引擎后才能成功地執(zhí)行,當(dāng)用戶請求一個擴(kuò)展名為.aspx的文件時這很自然地發(fā)生。然而,如果要讓用戶輸入一個實(shí)際并不存在的網(wǎng)址,通過網(wǎng)址重寫到另一個存在的aspx頁面,你必須為該請求創(chuàng)建相應(yīng)的目錄和默認(rèn)的Default.aspx頁面,除非配置IIS讓它把所有的請求都轉(zhuǎn)交給IIS處理,但是這種方式盲目地將所有請求都轉(zhuǎn)交給了ASP.NET引擎。

關(guān)鍵字:ASP.NET、網(wǎng)站、IIS、URL

分享到:

頂部 】 【 關(guān)閉
版權(quán)所有:佛山思海電腦網(wǎng)絡(luò)有限公司 ©1998-2024 All Rights Reserved.
聯(lián)系電話:(0757)22630313、22633833
中華人民共和國增值電信業(yè)務(wù)經(jīng)營許可證: 粵B1.B2-20030321 備案號:粵B2-20030321-1
網(wǎng)站公安備案編號:44060602000007 交互式欄目專項(xiàng)備案編號:200303DD003  
察察 工商 網(wǎng)安 舉報(bào)有獎  警警  手機(jī)打開網(wǎng)站