1. 程式人生 > >剛註冊,先轉發一片文章:在 ASP.NET 中執行 URL 重寫

剛註冊,先轉發一片文章:在 ASP.NET 中執行 URL 重寫

在 ASP.NET 中執行 URL 重寫

Scott Mitchell

4GuysFromRolla.com

適用範圍:

Microsoft® ASP.NET

摘要:介紹如何使用 Microsoft ASP.NET 執行動態 URL 重寫。URL 重寫是擷取傳入 Web 請求並自動將請求重定向到其他 URL 的過程。討論實現 URL 重寫的各種技術,並介紹執行 URL 重寫的一些實際情況。

*
本頁內容

引言

讓我們花點時間來看一下網站上的一些 URL。您是否發現一些類似於 http://yoursite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&type=summary 的 URL?或者,您可能將一系列網頁從一個目錄或網站移動到另一個目錄或網站,結果導致已將舊 URL 用作書籤的訪問者斷開連結。在本文中,我們將瞭解如何通過將 http://yoursite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&type=summary 替換為類似於 http://yoursite.com/people/sales/chuck.smith 的網址,使用 URL 重寫將那些冗長的 URL 縮寫為富有意義且容易記憶的 URL。我們還將瞭解如何將 URL 重寫用於建立智慧 404 錯誤。

URL 重寫是擷取傳入 Web 請求並自動將請求重定向到其他資源的過程。執行 URL 重寫時,通常會檢查被請求的 URL,並基於 URL 的值將請求重定向到其他 URL。例如,在進行網站重組而將 /people/ 目錄下的所有網頁移動到 /info/employees/ 目錄中時,您可能希望使用 URL 重寫來檢查 Web 請求是否指向了 /people/ 目錄中的檔案。如果請求指向 /people/ 目錄中的檔案,您可能希望自動將請求重定向到 /info/employees/ 目錄中的同一檔案。

使用傳統的 ASP,應用 URL 重寫的唯一方法是編寫 ISAPI 篩選器,或者購買提供 URL 重寫功能的第三方產品。但是,使用 Microsoft® ASP.NET,您可以通過很多方法來輕鬆地建立您自己的 URL 重寫軟體。本文討論了可供 ASP.NET 開發人員實現 URL 重寫的各種技術,然後討論了 URL 重寫的一些實際使用情況。在深入討論 URL 重寫的技術細節之前,讓我們先看一些可以使用 URL 重寫的日常情景。

返回頁首返回頁首

URL 重寫的常見用法

建立資料驅動的 ASP.NET 網站時,通常會產生一個單個的網頁,該網頁基於查詢字串引數顯示資料庫資料的子集。例如,在設計電子商務站點時,您的任務之一便是允許使用者瀏覽待售產品。為此,您可以建立一個名為 displayCategory.aspx 的頁面,該頁面將顯示給定類別的產品。可以通過查詢字串引數來指定要檢視的該類別的產品。也就是說,如果使用者要瀏覽待售的 Widget 產品,並且所有 Widget 產品的 CategoryID 均為 5,則使用者可以訪問以下網址:http://yousite.com/displayCategory.aspx?CategoryID=5。

建立具有此類 URL 的網站有兩點不足:首先,從終端使用者的角度考慮,URL http://yousite.com/displayCategory.aspx?CategoryID=5 比較雜亂。可用性專家 Jakob Neilsen建議遵循以下標準來選擇 URL:

簡短。

易於鍵入。

可以看出站點的結構。

“可刪節”,允許使用者通過刪除 URL 的組成部分來瀏覽站點。

我還要增加一條標準,即,URL 應該便於記憶。URL http://yousite.com/displayCategory.aspx?CategoryID=5 不符合 Neilsen 的任何標準,也不容易記住。要求使用者鍵入查詢字串值將使 URL 的鍵入變得非常困難,並且只有瞭解查詢字串引數的用途及其名稱/值對結構的富有經驗的 Web 開發人員才能夠對 URL 進行“刪節”。

較好的方法是允許使用切合實際且容易記憶的 URL,如 http://yoursite.com/products/Widgets。只要看一眼 URL,您便可以推斷出將要顯示的內容 -- 有關 Widget 的資訊。此 URL 也很容易記住和共享。我可以告訴我的同事“請檢視 yoursite.com/products/Widgets,”,她可能無需再次問我 URL 是什麼即可開啟該頁面。(嘗試一下,您只需說出“Amazon.com 頁面”即可!)此 URL 還將顯示出來,並且應該是“可刪節”的。也就是說,如果使用者刪去 URL 的末端,鍵入 http://yoursite.com/products,他們應該看到所有產品的列表,或者至少應該看到他們可以檢視的所有類別的產品列表。

注意:要獲得“可刪節”URL 的最好示例,可考慮使用由許多 blog 引擎生成的 URL。要檢視 2004 年 1 月 28 日的帖子,使用者可以訪問諸如 http://someblog.com/2004/01/28 的 URL。如果該 URL 被刪節為 http://someblog.com/2004/01,使用者將看到 2004 年 1 月的所有帖子。將該 URL 進一步刪節為 http://someblog.com/2004 將顯示 2004 年的所有帖子。

除了簡化 URL 之外,URL 重寫還經常用於處理網站重組,以免導致大量連結斷開或書籤過期。

返回頁首返回頁首

請求到達 IIS 時將會發生什麼情況

在正式研究 URL 如何實現重寫之前,應首先了解 Microsoft® Internet Information Services (IIS) 如何處理傳入請求,這一點非常重要。當請求到達 IIS Web 伺服器時,IIS 檢查被請求檔案的副檔名以確定如何處理該請求。IIS 可以自行處理請求(如 HTML 頁面、影象以及其他靜態內容),或者將請求路由到 ISAPI 擴充套件。(ISAPI 擴充套件是一個處理傳入 Web 請求的非託管編譯類。其任務是生成被請求資源的內容。)

例如,當傳入針對 Info.asp 網頁的請求時,IIS 會將此訊息路由到 asp.dll ISAPI 擴充套件。然後,該 ISAPI 擴充套件將載入被請求的 ASP 頁面,執行該頁面,並將所呈現的 HTML 返回給 IIS,然後,IIS 將該 HTML 傳送回請求客戶端。對於 ASP.NET 頁面,IIS 會將此訊息路由到 aspnet_isapi.dll ISAPI 擴充套件。然後,aspnet_isapi.dll ISAPI 擴充套件將處理操作傳遞給託管的 ASP.NET 輔助程序,該輔助程式將處理請求,並返回 ASP.NET 網頁的呈現 HTML。

您可以自定義 IIS,以指定副檔名與 ISAPI 擴充套件的對映關係。圖 1 顯示了 Internet Information Services 管理工具的“應用程式配置”對話方塊。請注意,與 ASP.NET 有關的副檔名(.aspx、ascx、config、asmx、rem、cs、vb 及其他)均已對映到 aspnet_isapi.dll ISAPI 擴充套件。


1. 已配置的副檔名對映

討論 IIS 如何管理傳入請求稍稍超出了本文範圍。但是可以在 Michele Leroux Bustamante 的文章 Inside IIS and ASP.NET 中找到對此內容的深入討論。ASP.NET 引擎僅處理那些副檔名已明確對映至 IIS 中的 aspnet_isapi.dll 的傳入 Web 請求,瞭解這一點非常重要。

使用 ISAPI 篩選器檢查請求

IIS 除了可以將傳入 Web 請求的副檔名對映到相應的 ISAPI 擴充套件之外,還將執行許多其他任務。例如,IIS 將嘗試對發出請求的使用者進行身份驗證,並確定通過身份驗證的使用者是否有許可權訪問被請求的檔案。在處理請求的有效期內,IIS 將經歷幾個狀態。在每個狀態下,IIS 都將引發可以使用 ISAPI 篩選器以程式設計方式進行處理的事件。

與 ISAPI 擴充套件一樣,ISAPI 篩選器是在 Web 伺服器上安裝的非託管程式碼塊。ISAPI 擴充套件被設計為可以響應針對特定檔案型別的請求。另一方面,ISAPI 篩選器還包含可以對 IIS 引發的事件進行響應的程式碼。ISAPI 篩選器可以擷取甚至修改傳入和傳出的資料。ISAPI 篩選器可以應用於很多方面,包括:

身份驗證和授權。

記錄和監視。

HTTP 壓縮。

URL 重寫。

雖然 ISAPI 篩選器可用於執行 URL 重寫,但本文將討論如何使用 ASP.NET 實現 URL 重寫。不過,我們將對使用 ISAPI 篩選器與使用 ASP.NET 中的技術實現 URL 重寫進行權衡。

請求進入 ASP.NET 引擎時將會發生什麼情況

在 ASP.NET 之前,需要使用 ISAPI 篩選器來實現 IIS Web 伺服器上的 URL 重寫。由於 ASP.NET 引擎與 IIS 非常相似,因此可以使用 ASP.NET 進行 URL 重寫。存在相似之處的原因在於 ASP.NET 引擎可以實現以下功能:

在處理請求時可以引發事件。

允許任意數量的 HTTP 模組處理所引發的事件,這與 IIS 的 ISAPI 篩選器相似。

將呈現被請求資源這項任務委託給 HTTP 處理程式,該處理程式與 IIS 的 ISAPI 擴充套件相似。

與 IIS 一樣,ASP.NET 引擎在請求的有效期內將會觸發事件,通過發訊號來表示其處理過程從一個狀態改變為了另一個狀態。例如,當 ASP.NET 引擎首次響應請求時,BeginRequest 事件將被觸發。接下來觸發的是 AuthenticateRequest 事件,該事件在已建立使用者標識時出現。(此外,還有大量的其他事件:AuthorizeRequestResolveRequestCacheEndRequest,等等。這些事件屬於 System.Web.HttpApplication 類;有關詳細資訊,請參閱位於以下網址的技術文件:HttpApplication Class Overview。)

正如上一部分所討論的,可以建立 ISAPI 篩選器以響應 IIS 引發的事件。同樣,ASP.NET 提供了 HTTP 模組,該模組可以響應由 ASP.NET 引擎引發的事件。可以將 ASP.NET Web 應用程式配置為具有多個 HTTP 模組。對於由 ASP.NET 引擎處理的每個請求,將初始化每個已配置的 HTTP 模組,並允許將事件處理程式繫結到處理請求期間所引發的事件。請注意,對每個請求均使用了許多內建 HTTP 模組。其中的一個內建 HTTP 模組是 FormsAuthenticationModule,該模組首先檢查是否使用了窗體身份驗證,如果使用,將檢查是否對使用者進行了身份驗證。如果沒有使用,會自動將使用者重定向到指定的登入頁面。

如上所述,通過使用 IIS,傳入請求將最終傳送給 ISAPI 擴充套件,而 ISAPI 擴充套件的任務是返回特定請求的資料。例如,在請求傳統的 ASP 網頁時,IIS 將請求傳遞給 asp.dll ISAPI 擴充套件,該擴充套件的任務是返回被請求的 ASP 頁面的 HTML 標記。ASP.NET 引擎使用相似的方法。初始化 HTTP 模組後,ASP.NET 引擎的下一項任務是確定應由哪個 HTTP 處理程式來處理請求。

所有通過 ASP.NET 引擎傳遞的請求最終都將到達 HTTP 處理程式或 HTTP 處理程式工廠(HTTP 處理程式工廠僅返回 HTTP 處理程式的例項,然後使用該例項來處理請求)。最終的 HTTP 處理程式將返回響應,即呈現被請求的資源。此響應將被髮送回 IIS,然後 IIS 將響應返回給提出請求的使用者。

ASP.NET 包括許多內建的 HTTP 處理程式。例如,PageHandlerFactory 用於呈現 ASP.NET 網頁。WebServiceHandlerFactory 用於呈現 ASP.NET Web 服務的響應 SOAP 信封。TraceHandler 將向 trace.axd 呈現請求的 HTML 標記。

圖 2 描述瞭如何處理對 ASP.NET 資源的請求。首先,IIS 接收到請求,並將請求排程給 aspnet_isapi.dll。接下來,ASP.NET 引擎對已配置的 HTTP 模組進行初始化。最後將呼叫正確的 HTTP 處理程式,並呈現被請求的資源,將所生成的標記返回給 IIS 和請求客戶端。


2. IIS 和 ASP.NET 正在處理請求

建立和註冊自定義 HTTP 模組和 HTTP 處理程式

建立自定義 HTTP 模組和 HTTP 處理程式是相對簡單的任務,包括建立實現正確介面的託管類。HTTP 模組必須實現 System.Web.IHttpModule 介面,而 HTTP 處理程式和 HTTP 處理程式工廠必須分別實現 System.Web.IHttpHandler 介面和 System.Web.IHttpHandlerFactory 介面。建立 HTTP 處理程式和 HTTP 模組的細節超出了本文的範圍。要獲得詳細的背景知識,請閱讀 Mansoor Ahmed Siddiqui 的文章 HTTP Handlers and HTTP Modules in ASP.NET

建立了自定義 HTTP 模組或 HTTP 處理程式之後,必須將其註冊到 Web 應用程式。為整個 Web 伺服器註冊 HTTP 模組和 HTTP 處理程式僅需在 machine.config 檔案中進行簡單的新增即可;而為特定 Web 應用程式註冊 HTTP 模組或 HTTP 處理程式包括嚮應用程式的 Web.config 檔案中新增幾行 XML。

特別要說明的是,要將 HTTP 模組新增到 Web 應用程式,應在 Web.config 的 configuration/system.web 部分新增以下幾行:

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

type 值提供了 HTTP 模組的程式集和類名稱,而 name 值提供了友好名稱,可以在 Global.asax 檔案中使用此友好名稱來引用 HTTP 模組。

Web.config 的 configuration/system.web 部分中的 <httpHandlers> 標記對 HTTP 處理程式和 HTTP 處理程式工廠進行了配置,如下所示:

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

如上所述,對於每個傳入請求,ASP.NET 引擎將確定應使用哪個 HTTP 處理程式來呈現請求。此決定是基於傳入請求的動詞和路徑做出的。動詞將指定所作出的 HTTP 請求的型別(GET 或 POST),而路徑將指定被請求檔案的位置和檔名。因此,如果我們希望 HTTP 處理程式處理對副檔名為 .scott 的檔案的所有請求(GET 或 POST),可以在 Web.config 檔案中新增下面幾行:

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

其中,type 是 HTTP 處理程式的型別。

注意:註冊 HTTP 處理程式時,應確保 HTTP 處理程式使用的副檔名已從 IIS 對映到 ASP.NET 引擎,這一點非常重要。也就是說,在本 .scott 示例中,如果 .scott 副檔名沒有從 IIS 對映到 aspnet_isapi.dll ISAPI 擴充套件,則對檔案 foo.scott 的請求將導致 IIS 試圖返回檔案 foo.scott 的內容。為了使 HTTP 處理程式可以處理此請求,必須將 .scott 副檔名對映到 ASP.NET 引擎。然後,ASP.NET 引擎將把請求正確地路由到相應的 HTTP 處理程式。

返回頁首返回頁首

實現 URL 重寫

可以使用 ISAPI 篩選器在 IIS Web 伺服器級別實現 URL 重寫,也可以使用 HTTP 模組或 HTTP 處理程式在 ASP.NET 級別實現 URL 重寫。本文重點介紹如何使用 ASP.NET 實現 URL 重寫,因此我們將不對使用 ISAPI 篩選器實現 URL 重寫的細節進行深入探討。但是,有大量的第三方 ISAPI 篩選器可用於 URL 重寫,例如:

通過 System.Web.HttpContext 類的 RewritePath() 方法,可以在 ASP.NET 級別實現 URL 重寫。HttpContext 類包含有關特定 HTTP 請求的 HTTP 特定資訊。對於 ASP.NET 引擎收到的每個請求,均為該請求建立一個 HttpContext 例項。此類具有如下屬性:RequestResponse,提供對傳入請求和傳出響應的訪問;ApplicationSession,提供對應用程式和會話變數的訪問;User,提供有關通過了身份驗證的使用者的資訊;其他相關屬性。

使用 Microsoft® .NET Framework Version 1.0,RewritePath() 方法可以接受單個字串作為要使用的新路徑。HttpContext 類的 RewritePath(string) 方法在內部對 Request 物件的 Path 屬性和 QueryString 屬性進行更新。除了 RewritePath(string),.NET Framework 1.1 還包括另一種形式的 RewritePath() 方法,此方法可以接受三個字串輸入引數。此備用過載形式不僅要設定 Request 物件的 Path 屬性和 QueryString 屬性,還要設定內部成員變數,這些變數用於計算 Request 物件的 PhysicalPathPathInfoFilePath 屬性值。

要在 ASP.NET 中實現 URL 重寫,需要建立 HTTP 模組或 HTTP 處理程式,以便完成以下操作:

1.

檢查被請求的路徑,以確定 URL 是否需要重寫。

2.

如果需要重寫,通過呼叫 RewritePath() 方法來重寫路徑。

例如,假設我們的網站中包含每個員工通過 /info/employee.aspx?empID=employeeID 均可訪問的資訊。為了使 URL 可以更多地被“刪節”,我們可以決定通過以下地址來訪問員工頁面:/people/EmployeeName.aspx。這就是我們要使用 URL 重寫的一個例子。也就是說,在請求 /people/ScottMitchell.aspx 頁面時,我們要重寫該 URL,以便使用 /info/employee.aspx?empID=1001 頁面。

使用 HTTP 模組執行 URL 重寫

在 ASP.NET 級別執行 URL 重寫時,可以使用 HTTP 模組或 HTTP 處理程式來執行重寫。使用 HTTP 模組時,必須決定在請求有效期內的哪個時間點上來檢查 URL 是否需要重寫。乍一看,這似乎可以任意選擇,但決定會以一種明顯而微妙的方式對應用程式產生影響。由於內建 ASP.NET HTTP 模組使用 Request 物件的屬性執行任務,因此選擇在何處執行重寫非常重要。(如上所述,重寫路徑將改變 Request 物件的屬性值。)下面列出了這些密切相關的內建 HTTP 模組及其捆綁到的事件:

HTTP 模組 事件 說明

FormsAuthenticationModule

AuthenticateRequest

確定使用者是否通過了窗體身份驗證。如果沒有,使用者將被自動重定向到指定的登入頁面。

FileAuthorizationMoudle

AuthorizeRequest

使用 Windows 身份驗證時,此 HTTP 模組將檢查以確保 Microsoft® Windows® 帳戶對被請求的資源具有足夠的許可權。

UrlAuthorizationModule

AuthorizeRequest

檢查以確保請求者可以訪問指定的 URL。通過 Web.config 檔案中的 <authorization> 和 <location> 元素來指定 URL 授權。

如上所述,BeginRequest 事件在 AuthenticateRequest 之前觸發,後者在 AuthenticateRequest 之前觸發。

可以執行 URL 重寫的一個安全位置是在 BeginRequest 事件中。也就是說,如果 URL 需要重寫,該操作將在任何一個內建 HTTP 模組執行後執行。使用窗體身份驗證時,這種方法存在一定的缺陷。如果您以前使用過窗體身份驗證,您會了解當使用者訪問受限資源時,他們將被自動重定向到指定的登入頁面。成功登入後,使用者將被返回到他們第一次嘗試訪問的頁面。

如果在 BeginRequestAuthenticateRequest 事件中執行 URL 重寫,登入頁面(提交後)將把使用者重定向到重寫後的頁面上。也就是說,假設使用者在其瀏覽視窗中鍵入了 /people/ScottMitchell.aspx,此地址將被重寫為 /info/employee.aspx?empID=1001。如果將 Web 應用程式配置為使用窗體身份驗證,當用戶第一次訪問 /people/ScottMitchell.aspx 時,首先,URL 將被重寫為 /info/employee.aspx?empID=1001;接下來,FormsAuthenticationModule 將執行,並將使用者重定向到登入頁面(如果需要)。但是,使用者在成功登入後將被髮送到 /info/employee.aspx?empID=1001,因為當 FormsAuthenticationModule 執行後,此 URL 即是請求的 URL。

同樣,在 BeginRequestAuthenticateRequest 事件中執行重寫時,UrlAuthorizationModule 看到的將是重寫後的 URL。也就是說,如果您在 Web.config 檔案中使用 <location> 元素來為特定的 URL 指定授權,則必須引用重寫後的 URL。

要解決這些細微問題,您可以決定在 AuthorizeRequest 事件中執行 URL 重寫。此方法解決了 URL 授權和窗體身份驗證的一些問題,但同時也產生了新的問題:檔案授權無法工作。使用 Windows 身份驗證時,FileAuthorizationModule 將檢查以確保通過身份驗證的使用者具有訪問特定 ASP.NET 頁面的相應許可權。

假設一組使用者對 C:\Inetput\wwwroot\info\employee.aspx 沒有 Windows 級別的檔案訪問許可權,並要嘗試訪問 /info/employee.aspx?empID=1001,他們將會收到授權錯誤訊息。但是,如果我們將 URL 重寫移到 AuthenticateRequest 事件中,當 FileAuthorizationModule 檢查安全設定時,仍然認為被請求的檔案是 people/ScottMitchell.aspx,因為該 URL 必須被重寫。因此,檔案授權檢查將通過,允許此使用者檢視重寫後的 URL /info/employee.aspx?empID=1001 的內容。

那麼,應該何時在 HTTP 模組中執行 URL 重寫?這取決於要使用的身份驗證型別。如果不想使用任何身份驗證,則無論 URL 重寫發生在 BeginRequestAuthenticateRequest 還是 AuthorizeRequest 中都沒有什麼關係。如果要使用窗體身份驗證而不使用 Windows 身份驗證,請將 URL 重寫放在 AuthorizeRequest 事件處理程式中執行。最後,如果要使用 Windows 身份驗證,請在 BeginRequestAuthenticateRequest 事件進行過程中安排 URL 重寫。

在 HTTP 處理程式中執行 URL 重寫

也可以由 HTTP 處理程式或 HTTP 處理程式工廠執行 URL 重寫。如上所述,HTTP 處理程式是負責生成特定型別請求的內容的類;HTTP 處理程式工廠是負責返回 HTTP 處理程式例項的類,該例項可以生成特定型別請求的內容。

在本文中,我們將對如何為 ASP.NET 網頁建立 URL 重寫 HTTP 處理程式工廠進行討論。HTTP 處理程式工廠必須實現 IHttpHandlerFactory 介面,此介面包括 GetHandler() 方法。初始化相應的 HTTP 模組後,ASP.NET 引擎將確定為給定的請求呼叫哪個 HTTP 處理程式或 HTTP 處理程式工廠。如果要呼叫 HTTP 處理程式工廠,ASP.NET 引擎將為 Web 請求呼叫傳入 HttpContext 的 HTTP 處理程式工廠的 GetHandler() 方法,以及一些其他資訊。然後,HTTP 處理程式工廠必須返回一個物件,該物件將實現可以處理請求的 IHttpHandler

要通過 HTTP 程式程式執行 URL 重寫,我們可以建立一個 HTTP 處理程式工廠,該處理程式工廠的 GetHandler() 方法將檢查被請求的路徑,以確定是否需要重寫 URL。如果需要,它可以呼叫傳入的 HttpContext 物件的 RewritePath() 方法,如前面所討論的。最後,HTTP 處理程式工廠可以返回由 System.Web.UI.PageParser 類的 GetCompiledPageInstance() 方法返回的 HTTP 處理程式。(此技術與內建 ASP.NET 網頁 HTTP 處理程式工廠 PageHandlerFactory 工作時所應用的技術相同。)

由於所有 HTTP 模組都將在例項化自定義 HTTP 處理程式工廠之前進行初始化,因此,在將 URL 重寫放在事件的後半段時,使用 HTTP 處理程式工廠就會帶來相同的風險,即檔案授權無法工作。因此,如果您依賴於 Windows 身份驗證和檔案授權,您可能希望為 URL 重寫使用 HTTP 模組方法。

在下一部分中,我們將對構建可重用的 URL 重寫引擎進行討論。在介紹了 URL 重寫引擎(可通過下載本文的程式碼獲得)之後,我們將在剩下的兩個部分中對 URL 重寫的實際使用情況進行介紹。首先,我們將討論如何使用 URL 重寫引擎,並介紹一個簡單的 URL 重寫示例。接下來,我們將利用重寫引擎的正則表示式功能來提供真正“可刪節”的 URL。

返回頁首返回頁首

構建 URL 重寫引擎

為了有助於描述如何在 ASP.NET Web 應用程式中實現 URL 重寫,我建立了 URL 重寫引擎。此重寫引擎將提供以下功能:

使用 URL 重寫引擎的 ASP.NET 頁面開發人員可以在 Web.config 檔案中指定重寫規則。

重寫規則可以使用正則表示式來實現功能強大的重寫規則。

可以輕鬆地將 URL 重寫配置為使用 HTTP 模組或 HTTP 處理程式。

在本文中,我們將介紹僅使用 HTTP 模組的 URL 重寫。要檢視如何使用 HTTP 處理程式來執行 URL 重寫,請參考可隨本文下載的程式碼。

為 URL 重寫引擎指定配置資訊

讓我們先介紹一下 Web.config 檔案中重寫規則的結構。首先,您需要在 Web.config 檔案中指明要使用 HTTP 模組還是 HTTP 處理程式來執行 URL 重寫。在下載程式碼中,Web.config 檔案包含兩個已註釋掉的條目:

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

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

註釋掉 <httpModules> 條目,以使用 HTTP 模組執行重寫;註釋掉 <httpHandlers> 條目,以使用 HTTP 處理程式執行重寫。

除了指定使用 HTTP 模組還是 HTTP 處理程式執行重寫外,Web.config 檔案還包含重寫規則:重寫規則由兩個字串組成:要在被請求的 URL 中查詢的模式;要替換此模式的字串(如果找到)。在 Web.config 檔案中,此資訊是使用以下語法表達的:

<RewriterConfig>
   <Rules>
   <RewriterRule>
      <LookFor>要查詢的模式</LookFor>
      <SendTo>要用來替換模式的字串</SendTo>
   </RewriterRule>
   <RewriterRule>
      <LookFor>要查詢的模式</LookFor>
      <SendTo>要用來替換模式的字串</SendTo>
   </RewriterRule>
   ...
   </Rules>
</RewriterConfig>

每個重寫規則均由 <RewriterRule> 元素表達。要搜尋的模式由 <LookFor> 元素指定,而要替換所找到的模式的字串將在 <SentTo> 元素中輸入。這些重寫規則將從頭到尾進行計算。如果發現與某個規則匹配,URL 將被重寫,並且對重寫規則的搜尋將會終止。

在 <LookFor> 元素中指定模式時,請注意,要使用正則表示式來執行匹配和字串替換。(稍後,我們將介紹一個真實的示例,說明如何使用正則表示式來搜尋模式。)由於模式是正則表示式,應確保轉義正則表示式中的任何保留字元。(一些正則表示式保留字元包括:.、?、^、$ 及其他。可以通過在前面加反斜槓(如 \.)對這些字元進行轉義,以匹配文字句點。)

使用 HTTP 模組執行 URL 重寫

建立 HTTP 模組與建立可以實現 IHttpModule 介面的類一樣簡單。IHttpModule 介面定義了兩種方法:

Init(HttpApplication)。此方法在初始化 HTTP 模組後觸發。在此方法中,您將把事件處理程式繫結到相應的 HttpApplication 事件。

Dispose()。當請求已完成並已傳送回 IIS 時呼叫此方法。您應當在此處執行所有最終的清除操作。

為了便於為 URL 重寫建立 HTTP 模組,我將從建立抽象基類 BaseModuleRewriter 開始介紹。此類將實現 IHttpModule。在 Init() 事件中,它將 HttpApplicationAuthorizeRequest 事件繫結到 BaseModuleRewriter_AuthorizeRequest 方法。BaseModuleRewriter_AuthorizeRequest 方法將呼叫該類傳入被請求的 PathRewrite() 方法,以及傳入 Init() 方法的 HttpApplication 物件。Rewrite() 方法是抽象的,也就是說,在 BaseModuleRewriter 類中,Rewrite() 方法沒有方法主體;從 BaseModuleRewriter 派生而來的類必須覆蓋此方法並提供方法主體。

具有此基類後,只需建立由 BaseModuleRewriter 派生的類即可,該類可以覆蓋 Rewrite() 並在那裡執行 URL 重寫邏輯。下面顯示了 BaseModuleRewriter 的程式碼。

public abstract class BaseModuleRewriter : IHttpModule
{
   public virtual void Init(HttpApplication app)
   {
      // 警告!此程式碼不適用於 Windows 身份驗證!
      // 如果使用 Windows 身份驗證,
      // 請改為 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 類將在 AuthorizeRequest 事件中執行 URL 重寫。如上所述,如果將 Windows 身份驗證與檔案授權結合使用,您需要對此做出更改,以便可以在 BeginRequestAuthenticateRequest 事件中執行 URL 重寫。

ModuleRewriter 類擴充套件了 BaseModuleRewriter 類,並負責執行實際的 URL 重寫。ModuleRewriter 包含單一覆蓋方法(Rewrite()),如下所示:

protected override void Rewrite(string requestedPath, 
   System.Web.HttpApplication app)
{
   // 獲得配置規則
   RewriterRuleCollection rules = 
     RewriterConfiguration.GetConfig().Rules;

   // 遍歷每個規則...
   for(int i = 0; i < rules.Count; i++)
   {
      // 獲得要查詢的模式,並且
      // 解析 Url(轉換為相應的目錄)
      string lookFor = "^" + 
        RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, 
        rules[i].LookFor) + "$";

      // 建立 regex(請注意,已設定 IgnoreCase...)
      Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);

      // 檢視是否找到了匹配的規則
      if (re.IsMatch(requestedPath))
      {
         // 找到了匹配的規則 -- 進行必要的替換
         string sendToUrl = 
RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, 
            re.Replace(requestedPath, rules[i].SendTo));

         // 重寫 URL
         RewriterUtils.RewriteUrl(app.Context, sendToUrl);
         break;      // 退出 For 迴圈
      }
   }
}

Rewrite() 方法從獲取 Web.config 檔案中的一組重寫規則開始。然後,它將遍歷重寫規則,每次遍歷一個,對於每個規則,它將獲取規則的 LookFor 屬性,並使用正則表示式來確定是否在被請求的 URL 中找到了匹配的規則。

如果找到了匹配的規則,將在具有 SendTo 屬性值的被請求路徑上執行正則表示式替換。然後,替換後的 URL 將被傳遞到 RewriterUtils.RewriteUrl() 方法中。RewriterUtils 是一個 helper 類,此類將提供一對由 URL 重寫 HTTP 模組和 HTTP 處理程式使用的靜態方法。RewriterUrl() 方法僅呼叫 HttpContext 物件的 RewriteUrl() 方法。

注意:您可能已注意到,執行正則表示式匹配和替換時,將呼叫 RewriterUtils.ResolveUrl()。此 helper 方法只替換具有應用程式路徑值的字串中的所有 ~ 例項。

URL 重寫引擎的整個程式碼可隨本文下載。我們已經介紹了大部分密切相關的元件,但還有一些其他元件(例如,對 Web.config 檔案中 XML 格式的重寫規則進行反序列化以使其成為物件的類),以及用於 URL 重寫的 HTTP 處理程式工廠。本文剩餘的三個部分將對 URL 重寫的實際使用情況進行介紹。

返回頁首返回頁首

使用 URL 重寫引擎執行簡單的 URL 重寫

為了實際演示 URL 重寫引擎,我們來構建一個使用簡單 URL 重寫的 ASP.NET Web 應用程式。假設我們所工作的公司通過網路銷售分類產品。這些產品分為以下幾個類別:

類別 ID 類別名稱

1

飲料

2

調味品

3

糖果

4

奶製品

...

...

假設我們已建立了名為 ListProductsByCategory.aspx 的 ASP.NET 網頁,該網頁在查詢字串中接受類別 ID 值,並顯示屬於該類的所有產品。因此,要檢視我們銷售的飲料的使用者可以訪問 ListProductsByCategory.aspx?CategoryID=1,而那些要檢視奶製品的使用者可以訪問 ListProductsByCategory.aspx?CategoryID=4。此外,還假設我們有一個名為 ListCategories.aspx 的頁面,該頁面列出了待售的所有產品類別。

很顯然,這是一個 URL 重寫事例,因為提供給使用者的 URL 沒有為使用者帶來任何意義,也沒有為他們提供任何“可刪節性”。因此,讓我們使用 URL 重寫,以便在使用者訪問 /Products/Beverages.aspx 時,他們的 URL 將被重寫為 ListProductsByCategory.aspx?CategoryID=1。我們可以在 Web.config 檔案中使用以下 URL 重寫規則來實現此功能。

<RewriterConfig>
   <Rules>
      <!-- 產品製表者規則 -->
      <RewriterRule>
         <LookFor>~/Products/Beverages\.aspx</LookFor>
         <SendTo>~/ListProductsByCategory.aspx?CategoryID=1</SendTo>
      </RewriterRule>
      <RewriterRule>
   </Rules>
</RewriterConfig>

正如您可以看到的,此規則將進行搜尋,以檢視使用者請求的路徑是否為 /Products/Beverages.aspx。如果是,它便將 URL 重寫為 /ListProductsByCategory.aspx?CategoryID=1。

注意:請注意,<LookFor> 元素對 Beverages.aspx 中的句點進行了轉義。這是因為在正則表示式模式中使用了 <LookFor> 值,並且句點是正則表示式中的特殊字元,該字元表示“匹配任意字元”,例如,與 URL /Products/BeveragesQaspx 匹配。通過轉義句點(使用 \.),可以表明我們要匹配的是文字句點,而不是任何舊的字元。

有了此規則之後,當用戶訪問 /Products/Beverages.aspx 時,頁面上將顯示待售的飲料。圖 3 顯示了訪問 /Products/Beverages.aspx 的瀏覽器的快照。請注意,在瀏覽器的位址列中,URL 將讀取 /Products/Beverages.aspx,但使用者實際看到的是 ListProductsByCategory.aspx?CategoryID=1 的內容。(實際上,Web 伺服器上根本不存在 /Products/Beverages.aspx 檔案!)


圖 3. 重寫 URL 之後請求類別

與 /Products/Beverages.aspx 相似,下面我們要為其他產品類別新增重寫規則。此操作僅包括在 Web.config 檔案的 <Rules> 元素內新增附加的 <RewriterRule> 元素。請參閱下載內容中的 Web.config 檔案,以獲取用於此演示的一組完整的重寫規則。

為了使 URL 更具可刪節性,最好使使用者只需從 /Products/Beverages.aspx 中刪除 Beverages.aspx 即可看到產品類別的列表。乍一看,這可能是一項很普通的任務(只需新增一個將 /Products/ 對映到 /ListCategories.aspx 的重寫規則即可)。但此操作存在一個微妙之處,即您必須首先建立一個 /Products/ 目錄,並在 /Products/ 目錄中新增一個空的 Default.aspx 檔案。

要理解需要執行這些額外步驟的原因,可以參考前面的內容,即 URL 重寫引擎位於 ASP.NET 級別上。也就是說,如果 ASP.NET 引擎永遠沒有機會處理請求,URL 重寫引擎就沒有辦法檢測傳入的 URL。而且,請記住,僅當被請求的檔案具有相應的副檔名時,IIS 才會將傳入請求傳遞給 ASP.NET 引擎。因此,如果使用者訪問 /Products/,而 IIS 沒有看到任何副檔名,那麼它將檢查目錄,以檢視是否存在這樣一個檔案,即該檔名為預設檔名中的一個。(Default.aspx、Default.htm、Default.asp 等等。“IIS 管理”對話方塊中“Web 伺服器屬性”對話方塊的“文件”選項卡對這些預設檔名進行了定義。)當然,如果 /Products/ 目錄不存在,IIS 將返回 HTTP 404 錯誤。

因此,我們需要建立 /Products/ 目錄。另外,我們還需要在此目錄中建立一個檔案 Default.aspx。這樣,當用戶訪問 /Products/ 時,IIS 將檢測目錄,檢視是否存在一個名為 Default.aspx 的檔案,然後將處理過程傳遞給 ASP.NET 引擎。然後,URL 重寫器將在重寫 URL 時分解。

建立目錄和 Default.aspx 檔案後,請繼續操作,並向 <Rules> 元素中新增以下重寫規則:

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

有了此規則之後,當用戶訪問 /Products/ 或 /Products/Default.aspx 時,他們將看到產品類別列表,如圖 4 所示。


4. 向 URL 新增“可刪節性”

處理回發

如果要重寫的 URL 中包含一個伺服器端的 Web 窗體並執行回發,則窗體回發後,將使用帶下劃線的 URL。也就是說,如果使用者在瀏覽器中輸入 /Products/Beverages.aspx,他們在瀏覽器位址列中看到的將是 /Products/Beverages.aspx,但是他們看到的內容將是 ListProductsByCategory.aspx?CategoryID=1 的內容。如果 ListProductsByCategory.aspx 執行了回發,使用者將被回發到 ListProductsByCategory.aspx?CategoryID=1,而不是 /Products/Beverages.aspx。這樣不會中斷任何內容,但從使用者的角度考慮,如果單擊按鈕時突然看到 URL 更改會使他們感到不安。

出現這種情況的原因是:在呈現 Web 窗體時,它會將其操作屬性直接設定為 Request 物件中檔案路徑的值。當然,在呈現 Web 窗體時,URL 已從 /Products/Beverages.aspx 重寫為 ListProductsByCategory.aspx?CategoryID=1,這表明 Request 物件報告使用者要訪問 ListProductsByCategory.aspx?CategoryID=1。只需使伺服器端窗體不呈現操作屬性即可解決此問題。(預設情況下,如果窗體不包含操作屬性,瀏覽器將會回發。)

不幸的是,Web 窗體不允許您明確指定操作屬性,也不允許您設定某些屬性以禁用操作屬性的呈現。因此,我們必須自己來擴充套件 System.Web.HtmlControls.HtmlForm 類,覆蓋 RenderAttribute() 方法並明確指出它不會呈現操作屬性。

由於繼承功能,我們可以獲得 HtmlForm 類的所有功能,並且只需新增幾行程式碼即可獲得所需的行為。以下顯示了自定義類的完整程式碼:

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 類的 RenderAttributes() 方法的準確程式碼,而不設定操作屬性。(我使用 Lutz Roeder 的 Reflector 來檢視 HtmlForm 類的原始碼。)

建立此類並對其進行編譯之後,要在 ASP.NET Web 應用程式中使用它,應首先將其新增到 Web 應用程式的 References 資料夾中。然後,要使用它來代替 HtmlForm 類,只需在 ASP.NET 網頁的頂部新增以下內容即可:

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

然後,將 <form runat="server">(如果有)替換為:

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

並將右邊的 </form> 標記替換為:

</skm:Form>

您可以在 ListProductsByCategory.aspx(包含在本文的下載程式碼中)中發現操作中的此自定義 Web Form 類。下載內容中還包含了用於無操作 Web Form 的 Visual Studio .NET 專案。

注意:如果要重寫的目標 URL 沒有執行回發,則無需使用此自定義 Web Form 類。

返回頁首返回頁首

建立真正“可刪節”的 URL

前一部分中介紹的簡單 URL 重寫顯示瞭如何輕鬆地為 URL 重寫引擎配置新的重寫規則。但在使用正則表示式時,重寫規則的真正功能才會發揮更大作用,本部分將對此進行探討。

Blog 在當今正變得越來越流行,似乎每個人都擁有自己的 blog。如果您不熟悉 blog:blog 是經常更新的個人頁面,通常作為聯機期刊。大多數 blog 只記錄每天發生的事情,還有一些 blog 可能關注於特定的主題(例如,電影回顧、體育團隊或計算機技術)。

可以在任何地點對 blog 進行更新,更新頻率為從每天幾次到每週一次或兩次,具體情況取決於作者。通常,blog 主頁將顯示最近的 10 個條目,但實際上,所有 blog 軟體均提供存檔,訪問者可以通過存檔讀取較早的帖子。Blog 是用於“可刪節”URL 的一個功能強大的應用程式。假設在搜尋 blog 的存檔時,您在 URL /2004/02/14.aspx 上發現了您自己。如果您發現自己在閱讀 2004 年 2 月 14 日的帖子,您是否覺得很驚訝?而且,您可能希望檢視 2004 年 2 月的所有帖子,在這種情況下,您可以嘗試將 URL 刪節為 /2004/02/。要檢視 2004 年的所有帖子,您可以嘗試訪問 /2004/。

維護 blog 時,最好為訪問者提供此級別的 URL“可刪節性”。許多 blog 引擎都提供此功能,但我們將討論如何使用 URL 重寫來實現此功能。

首先,我們需要一個 ASP.NET 網頁,此頁面將按照日、月或年來顯示 blog 條目。假設我們有一個 ShowBlogContent.aspx 頁面,該頁面的查詢字串引數為年、月和日。要檢視 2004 年 2 月 14 日的帖子,我們可以訪問 ShowBlogContent.aspx?year=2004&month=2&day=14。要檢視 2004 年 2 月的所有帖子,我們可以訪問 ShowBlogContent.aspx?year=2004&month=2。最後,要檢視 2004 年的所有帖子,我們可以瀏覽到 ShowBlogContent.aspx?year=2004。(可以在本文的下載內容中找到 ShowBlogContent.aspx 的程式碼。)

在這種情況下,如果使用者訪問 /2004/02/14.aspx,我們需要將 URL 重寫為 ShowBlogContent.aspx?year=2004&month=2&day=14。所有三種情況(URL 指定了年、月和日時;URL 僅指定了年和月時;URL 僅指定了年時)均可使用重寫規則進行處理:

<RewriterConfig>
   <Rules>
      <!-- Blog 內容顯示程式規則 -->
      <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>

這些重寫規則表明了正則表示式的功能。在第一個規則中,我們使用模式 (\d{4})/(\d{2})/(\d{2})\.aspx 查詢 URL。在簡明英語中,它對應了這樣一個字串:首先是四個數字,後跟一個斜槓,然後是兩個數字,後跟一個斜槓,然後再跟兩個數字,最後是一個 .aspx。每個數字組周圍的括號非常重要,通過它可以在相應的 <SendTo> 屬性中引用這些括號內的匹配字元。 特別是,我們可以針對第一、第二和第三個括號組分別使用 $1、$2 和 $3 引用回括號內的匹配組。

注意:由於 Web.config 檔案採用 XML 格式,但是必須對元素文字部分中的字元(如 &、< 和 >)進行轉義。在第一個規則的 <SendTo> 元素中,& 被轉義為 &amp;。在第二個規則的 <SendTo> 中使用了另外一種技術(使用 <![CDATA[...]]> 元素),無需對內部的內容進行轉義。可以使用兩種方法中的任何一種,並且都會得到相同的結果。

圖 5、6 和 7 顯示了操作中的 URL 重寫。資料實際上是從我的 blog http://scottonwriting.net/ 中拖過來的。圖 5 中顯示了 2003 年 11 月 7 日的帖子;圖 6 中顯示了 2003 年 11 月的所有帖子;圖 7 顯示了 2003 年的所有帖子。


5. 2003 年 11 月 7 日的帖子


6. 2003 年 11 月的所有帖子


7. 2003 年的所有帖子

注意:URL 重寫引擎在 <LookFor> 元素中需要使用正則表示式模式。如果您對正則表示式不熟悉,可以閱讀我在早些時候編寫的一篇文章 An Introduction to Regular Expressions。另外,還有一個很好的網站:RegExLib.com,在那裡您可以獲取有關常用正則表示式的幫助資訊,還可以共享您自己的自定義正則表示式。

構建必備的目錄結構

當請求 /2004/03/19.aspx 時,IIS 將通知 .aspx 擴充套件,並將請求路由到 ASP.NET 引擎。請求在 ASP.NET 引擎的管道中移動時,URL 將被重寫為 ShowBlogContent.aspx?year=2004&month=03&day=19,並且訪問者會看到 2004 年 3 月 19 日的 blog 條目。但是當用戶瀏覽到 /2004/03/ 時將會發生什麼情況呢?除非有一個 /2004/03/ 目錄,否則 IIS 將返回一個 404 錯誤。此外,此目錄中還需要具有 Default.aspx 頁面,以便可以將請求傳遞給 ASP.NET 引擎。

因此,要使用這種方法,必須手動建立一個用於每年的目錄(其中包含 blog 條目),並且目錄中具有一個 Default.aspx 頁面。另外,在每年目錄中,您需要再手動建立十二個目錄(01、02、?、?...、12),並且每個目錄中均有一個 Default.aspx 檔案。(如上所述,我們還必須執行前面演示中的操作,即在 /Products/ 目錄中新增一個 Default.aspx 檔案,以便訪問 /Products/ 時可以正確顯示 ListCategories.aspx。)

很顯然,新增這樣一個目錄結構可能是一件很痛苦的事情。解決此問題的方法是使所有傳入的 IIS 請求都對映到 ASP.NET 引擎。通過這種方法,即使訪問 URL /2004/03/,IIS 也會如實地將請求傳遞給 ASP.NET 引擎(即使並不存在 /2004/03/ 目錄)。但是,使用這種方法將使 ASP.NET 引擎負責處理到達 Web 伺服器的所有型別的傳入請求,包括影象、CSS 檔案、外部 JavaScript 檔案、Macromedia Flash 檔案,等等。

對處理所有檔案型別的全面討論遠遠超出了本文的範圍。有關使用此技術的 ASP.NET Web 應用程式的示例,請參閱 .Text,一個開放源 blog 引擎。.Text 可以配置為將所有請求均對映到 ASP.NET 引擎。它可以使用自定義 HTTP 處理程式來處理生成所有檔案型別的問題,自定義 HTTP 處理程式瞭解如何生成典型的靜態檔案型別(影象、CSS 檔案,等等)。

返回頁首返回頁首

結論

在本文中,我們討論瞭如何在 ASP.NET 級別通過 HttpContext 類的 RewriteUrl() 方法來執行 URL 重寫。正如我們所看到的,RewriteUrl() 更新了特定的 HttpContext's Request 屬性,從而更新了被請求的檔案和路徑。最終結果是,從使用者角度來看,他們要訪問某個特定的 URL,但從 Web 伺服器端來看,被請求的卻是另一個 URL。

可以在 HTTP 模組或 HTTP 處理程式中重寫 URL。在本文中,我們介紹瞭如何使用 HTTP 模組執行重寫,並討論了在管道中的不同階段執行重寫的結果。

當然,如果執行 ASP.NET 級別的重寫,則僅當已成功地將請求從 IIS 傳遞給 ASP.NET 引擎後才會發生 URL 重寫。實際上,只有使用者請求帶 .aspx 副檔名的頁面時才會出現這種情況。但是,如果您要使使用者可以進入實際並不存在的 URL,但又希望重寫到現有的 ASP.NET 頁面,則必須建立虛擬目錄和 Default.aspx 頁面,或者對 IIS 進行配置,以使所有傳入請求一律被路由到 ASP.NET 引擎。

返回頁首返回頁首

參考資料

參考資料

URL 重寫是涉及到 ASP.NET 和競爭伺服器端 Web 技術的一個主題。例如,Apache Web 伺服器提供了名為 mod_rewrite 的 URL 重寫模組。Mod_rewrite 是一個功能強大的重寫引擎,提供了基於條件(如 HTTP 標題和伺服器變數)的重寫規則以及使用正則表示式的重寫規則。有關 mod_rewrite 的詳細資訊,請查閱 A User's Guide to URL Rewriting with the Apache Web Server

作者簡介

Scott Mitchell 著有五本書,他還是 4GuysFromRolla.com 網站的建立者。在過去五年中,他一直從事 Microsoft Web 技術方面的研究工作。Scott 是一位獨立的顧問、培訓師和作家。您可以通過 [email protected] 與作者進行聯絡,或者通過作者的 blog 進行聯絡,其網址是:http://scottonwriting.net/

相關推薦

註冊轉發文章ASP.NET 執行 URL 重寫

在 ASP.NET 中執行 URL 重寫 Scott Mitchell 4GuysFromRolla.com 適用範圍: Microsoft® ASP.NET 摘要:介紹如何使用 Microsoft ASP.NET 執行動態 URL 重寫。URL 重寫是擷取傳入 Web 請求並自動將請求

文章教你爬蟲入門學習原來這麼簡單!

好多朋友在入門python的時候都是以爬蟲入手,而網路爬蟲是近幾年比較流行的概念,特別是在大資料分析熱門起來以後,學習網路爬蟲的人越來越多,哦對,現在叫資料探勘了!   其實,一般的爬蟲具有2個功能:取資料和存資料!好像說了句廢話。。。 而從這2個功能拓展,需要的知識就很

再弄文章湊個4篇文章的數主要是用於XML和 Binary序列化和反序列化的類

using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Xml.Serialization; namespace NOAS.PublicOpinionMonit

最近在寫一些樹上的東西波LCA的吧!

++ html str long ace efi algorithm quest http 不會樹剖的我只有去學tarjan和倍增了,個人覺得倍增比tarjan好打一點。。。 tarjan學習的地方 http://www.cnblogs.com/JVxie/p/485471

解析微服務架構元件看這文章就夠

  1. 如何釋出和引用服務   服務描述:服務呼叫首先解決的問題就是服務如何對外描述。 常用的服務描述方式包括 RESTful API、XML 配置以及 IDL 檔案三種。   RESTful API   主要被用作 HTT

北大程式設計師兩段大廠實習經歷現在沒offer感覺前途灰暗

今日看到這樣一則帖子,北大畢業生找不到工作,在網上吐槽自己的遭遇,按道理像這種世界名校出來的學生找份工作不是輕輕鬆鬆,估計隨便哪怕就是網際網路大廠也是想進就進吧,我們可以看看這位北大畢業生的吐槽。   這名吐槽的樓主身份認證為北京大學:兩段大廠實習經歷,結果現在零offer,

[記錄] HoloLens呼叫攝像頭後拍攝到

在HoloLens上,開啟攝像機後,拍攝畫面,但是拍到一團黑,然後我將WebCamTex的尺寸和WebCameraDevices.Length列印到一個Text上 打印出來顯示:WebCameraTexture的寬和高都是16,WebCameraDdvices.Length為1,所以肯定是有外部

音視訊開發著作《Android音視訊開發》終於發售了波簽名送書福利!

經歷了兩年多,我的著作終於和大家見面了,寫書是一件很磨練人耐力的事情,從打算寫一本書開始後,心裡無時不刻有一塊大石頭壓在頭頂。一來要保證專業性,二來要保證質量,同時還要兼具備怎麼表達,才能讓別人明白所說的意思。所以看起來沒有那麼簡單。近年來,直播,短視訊行業相關

C語言實現掃雷遊戲要求第一次不踩雷能展開雷區(望各位大佬斧正)

對於實現掃雷遊戲思路如下: 首先佈置一定大小的掃雷區如9*9 隨機(rand())佈置一定數量的雷 實現掃雷(其中要求第一次踩不到雷,能展開一片無雷區) 其具體操作如下: 建立game.h, game.c, test.c檔案以便整理 在test.c檔案中:

有C/C++/Java基礎的學習Python文章就夠了

我在學校裡學習的是C、C++、C#,實習的時候公司裡用的都是Java,於是又自學了java。用我領導的一句話說,“C++轉Java幾天時間就夠了”。最近在學習深度學習演算法和自然語言處理的時候,很多演算法都是用python寫的,於是又下定決定學習了python。

一直對zookeeper的應用和原理比較迷糊今天看文章講得很通透分享如下

場景一 有這樣一個場景:系統中有大約100w的使用者,每個使用者平 均有3個郵箱賬號,每隔5分鐘,每個郵箱賬需要收取100封郵件,最多3億份郵件需要下載到伺服器中(不含附件和正文)。用20臺機器劃分計算的壓力,從 多個不同的網路出口進行訪問外網,計算的壓力得到緩解,那麼

大資料初學者福利文章教你搭建Hadoop大資料處理環境

由於Hadoop需要執行在Linux環境中,而且是分散式的,因此個人學習只能裝虛擬機器,本文都以VMware Workstation為準,安裝CentOS7,具體的安裝此處不作過多介紹,只作需要用到的知識介紹。 VMware的安裝,裝好一個虛擬機器後利用複製虛擬機器的方式建立後面幾個虛擬機器,省

文章叫你玩轉JQuery

1.為什麼要學習jQuery?     js的缺點:         1)花費10天時間開發設計,js中有很多的漏洞;不適合於大系統的開發。         2)獲取dom元素時,是很不靈活的,主要通過4個方法。         3)方法的長度太長,記憶難度比較大。    

tomcat問題jsp頁面無法編譯web頁面空白log顯示空指標在tomacat的work資料夾下沒有生成相應的Java檔案

主要是  3個錯誤:1.  !ENTRY org.eclipse.ui 4 0 2013-08-06 20:41:20.643 2.  !ENTRY org.eclipse.jst.jsp.core 4 4 2013-08-09 16:54:04.4903. !ENTRY

如何在三年內獲得十年工作經驗? (非常好的文章

作者 think12 關注 在如今的工作和生活中,“天下武功,唯快不破”成了我們的追求目標。我們都希望在短期內速成,什麼“21天成就xxx”、“xxx技能100天速成”廣受歡迎,我們甚至期望一夜之間變得學富五車、才高八斗、一夜暴富。我們都知道這是不符合常理的

企業公有云服務的構建“捷徑”看這文章就夠了

最近在上海舉辦的2018世界人工智慧大會,可謂是大佬雲集,金句頻出。在成為業內焦點的同時,也再次

真的Kafka 入門文章就夠了

初識 Kafka 什麼是 Kafka Kafka 是由 Linkedin 公司開發的,它是一個分散式的,支援多分割槽、多副本,基於 Zookeeper 的分散式訊息流平臺,它同時也是一款開源的基於釋出訂閱模式的訊息引擎系統。 Kafka 的基本術語 訊息:Kafka 中的資料單元被稱為訊息,也被稱為記錄,

今天看到的文章位資深程序員大牛給予Java初學者的學習路線建議

iyu 沒有 大牛 con ali spm 在找工作 mave ssm 一位資深程序員大牛給予Java初學者的學習路線建議 今天,現在的我,學了SSM集合框架,正在學MAVEN,正在找工作,作為一只女程序猿,看到這篇文章,仿佛沒有那麽迷茫,也更堅定了信心。加油!繼續學習,充

文章弄懂 JavaScript 的 import

import 語句用於匯入由另一個模組匯出的繫結。無論是否聲明瞭 strict mode,匯入的模組都執行在嚴格模式下。import語句不能在嵌入式指令碼中使用。 語法 import defaultExport from “module-name”; import * as name from “m

碼阻塞萬碼等待ASP.NET Core 同步方法呼叫非同步方法“死鎖”的真相

在我們 2015 年開始的從 .NET Framework 向 .NET Core 遷移的工程中,遇到的最大的坑就是標題中所說的——同步方法中呼叫非同步方法發生”死鎖”。雖然在 .NET Framework 時代就知道不能在同步方法中呼叫非同步方法,但我們卻明知路有坑,偏向此路行。不是我們自討苦吃,而是被迫無