ASP.NET 請求處理管道核心由 **HttpModule** (橫切關注點) 和 **HttpHandler** (終點處理) 組成。本文系統梳理 IIS 6/7+ 管道差異、核心接口、生命周期事件、配置方式、自定義模塊/處理程序實戰模式,並對比經典 ASP 請求流程。
請求處理流程對比
| 階段 | 經典 ASP (IIS 5/6) | ASP.NET (IIS 7+ 集成管道) |
| 入口 | inetinfo.exe (WWW 服務) | http.sys (內核驅動) → WAS |
| 分發 | asp.dll (ISAPI) | aspnet_isapi.dll → 托管管道 |
| 托管入口 | 無 | HttpRuntime → HttpApplicationFactory |
| 模塊鏈 | 無 | HttpModule (IHttpModule) 事件鏈 |
| 處理程序 | asp.dll 解釋執行 | HttpHandler (IHttpHandler) + HandlerFactory |
| 輸出 | 直接寫響應 | HttpHandler.ProcessRequest → Response |
HttpModule 詳解
- 實現 `IHttpModule` 接口:`Init(HttpApplication app)` 掛載事件、`Dispose()` 清理。
- 可掛載 `HttpApplication` 20+ 事件:`BeginRequest`、`AuthenticateRequest`、`AuthorizeRequest`、`AcquireRequestState` (Session 可用)、`PreRequestHandlerExecute`、**`PostRequestHandlerExecute`** (Handler 執行完)、`EndRequest` 等。
- **典型用途**:URL 重寫、身份驗證/授權、日志記錄、壓縮 (Gzip/Deflate)、靜態文件緩存頭、防盜鏈、請求計時/監控。
自定義模塊示例
public class HelloWorldModule : IHttpModule
{
public void Init(HttpApplication app)
{
app.BeginRequest += (src, e) => {
var ctx = ((HttpApplication)src).Context;
ctx.Response.Write("HelloWorldModule: Begin Request
");
};
app.EndRequest += (src, e) => {
var ctx = ((HttpApplication)src).Context;
ctx.Response.Write("
HelloWorldModule: End Request
");
};
}
public void Dispose() { }
}
配置註冊 (web.config)
<system.webServer> <!-- IIS 7+ 集成模式 -->
<modules>
<add name="HelloWorldModule" type="HelloWorldModule" />
<remove name="FormsAuthentication" /> <!-- 移除默認模塊 -->
</modules>
</system.webServer>
<system.web> <!-- IIS 6 經典模式 -->
<httpModules>
<add name="HelloWorldModule" type="HelloWorldModule" />
</httpModules>
</system.web>
HttpHandler 詳解
- 實現 `IHttpHandler`:`bool IsReusable { get; }`、`void ProcessRequest(HttpContext context)`。
- **處理程序工廠** `IHttpHandlerFactory`:`GetHandler`/`ReleaseHandler`,ASP.NET 內置 `PageHandlerFactory` 處理 `.aspx`、`WebServiceHandlerFactory` 處理 `.asmx`、`HttpRemotingHandlerFactory` 處理 `.soap`。
- **映射規則**:``,請求 `xxx.custom` 直接進入 `MyHandler.ProcessRequest`,**繞過頁面生命周期**,性能極高。
- **典型用途**:圖片動態生成 (驗證碼/圖表)、文件下載/斷點續傳、RSS/Atom Feed、REST API 端點、靜態資源合並壓縮。
自定義處理程序示例 (輸出當前時間 JSON)
public class TimeHandler : IHttpHandler
{
public bool IsReusable => true; // 無狀態可復用
public void ProcessRequest(HttpContext ctx)
{
ctx.Response.ContentType = "application/json";
ctx.Response.Write($"{{\"time\":\"{DateTime.Now:yyyy-MM-dd HH:mm:ss}\",\"utc\":\"{DateTime.UtcNow:o}\"}}");
}
}
<system.webServer>
<handlers>
<add name="TimeHandler" verb="GET" path="api/time" type="TimeHandler" preCondition="integratedMode" />
</handlers>
</system.webServer>
Module 與 Handler 交互關鍵點
- 請求先經 **所有 Module 事件鏈** (按配置順序),到達 `PostMapRequestHandler` 事件時確定 Handler。
- Handler `ProcessRequest` 執行期間,Module 事件**暫停**;Handler 返回後繼續 `PostRequestHandlerExecute` 等後續事件。
- Module 可在 `PreRequestHandlerExecute` 修改 `Context.Handler` **動態切換處理程序** (如權限不足切換到錯誤頁 Handler)。
- `HttpContext.Current.Handler` 可獲取當前正在執行的 Handler 實例。
默認 HttpModule 清單 (machine.config)
| 模塊 | 功能 |
| DefaultAuthenticationModule | 確保 Context.User 存在 |
| FormsAuthenticationModule | 表單認證票據處理 |
| WindowsAuthenticationModule | Windows/IIS 集成認證 |
| SessionStateModule | Session 狀態管理 |
| UrlAuthorizationModule | 基于 URL 的授權 (``) |
| FileAuthorizationModule | NTFS 文件權限檢查 |
| PassportAuthenticationModule | Passport 認證 (已廢棄) |
| ProfileModule | 用戶配置文件 |
| AnonymousIdentificationModule | 匿名用戶標識 |
最佳實踐與避坑
- **輕量級 Module**:`Init` 中只掛載必要事件,避免在 `BeginRequest` 做重 IO/數據庫操作,拖慢所有請求。
- **異步 Module** (`.NET 4.5+`):實現 `IHttpAsyncModule` 或在事件中 `await` 異步操作,釋放線程池。
- **Handler 復用**:`IsReusable=true` 僅限無狀態、線程安全 Handler;有狀態 (如持有 DbContext) 必須 `false`。
- **配置分離**:開發/測試/生產環境用 `web.config` transform 註冊不同 Module/Handler 集合。
- **錯誤處理**:Module 中 `try-catch` 記錄日志,避免未捕獲異常導致整個請求管道崩潰。