許多 ASP.NET 開發者習慣在頁面層級撰寫程式碼,卻對請求在伺服器端的完整生命週期知之甚少。理解 ASP.NET 管線事件、HttpHandler 與 HttpModule,能讓我們從「頁面級開發」進階為「請求級架構」,實現跨頁面的共用邏輯、URL 重寫、防盜鏈、認證授權等進階功能。
從瀏覽器發出請求到回應完成,ASP.NET 會依序觸發以下事件(IIS 7+ 整合模式下):
BeginRequest:請求開始AuthenticateRequest:身分驗證PostAuthenticateRequestAuthorizeRequest:授權檢查PostAuthorizeRequestResolveRequestCache:輸出快取解析PostResolveRequestCacheMapRequestHandler:依副檔名對應 HttpHandler(第 10 步)PostMapRequestHandlerAcquireRequestState:取得 Session 等狀態PostAcquireRequestStatePreRequestHandlerExecuteProcessRequest 方法(第 15 步)PostRequestHandlerExecuteReleaseRequestState:釋放狀態PostReleaseRequestStateUpdateRequestCache:更新輸出快取PostUpdateRequestCacheEndRequest:請求結束(唯一保證觸發的事件)PreSendRequestHeaders、PreSendRequestContent:發送回應前關鍵提醒:事件順序固定,但中途若呼叫 Response.End() 或發生未處理例外,後續事件將不再觸發。
HttpHandler 實作 IHttpHandler 介面,負責處理特定副檔名(如 .aspx、.ashx、.jpg)的請求。在 web.config 的 <httpHandlers> 區段定義對應關係:
<httpHandlers>
<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory" />
<add verb="*" path="*.ashx" type="System.Web.UI.SimpleHandlerFactory" />
<add verb="*" path="*.jpg" type="MyNamespace.ImageHandler, MyAssembly" />
</httpHandlers>
觸發時機:管線第 10 步 (MapRequestHandler) 選擇 Handler,第 15 步執行 ProcessRequest。
攔截所有 .jpg 請求,檢查 Referer 標頭,非本站來源則回傳預設圖片:
public class AntiHotlinkHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string filePath = context.Server.MapPath(context.Request.FilePath);
var referer = context.Request.UrlReferrer;
if (referer == null || !referer.Host.Contains("yourdomain.com"))
{
context.Response.ContentType = "image/gif";
context.Response.WriteFile("/images/hotlink-denied.gif");
return;
}
context.Response.ContentType = "image/jpeg";
context.Response.WriteFile(filePath);
}
public bool IsReusable => true; // 可重用,減少物件建立開銷
}
註冊於 web.config:
<add verb="*" path="*.jpg" type="MyProject.AntiHotlinkHandler, MyProject" />
| 特性 | HttpHandler | HttpModule |
|---|---|---|
| 作用範圍 | 特定副檔名/路徑 | 所有請求 |
| 介面 | IHttpHandler | IHttpModule |
| 觸發點 | 管線固定步驟 (10/15) | 可訂閱任一管線事件 |
| 典型用途 | 輸出圖片、RSS、自訂副檔名 | 認證、日誌、URL 重寫、壓縮、Session 管理 |
public class CustomAuthModule : IHttpModule
{
public void Init(HttpApplication context)
{
// 訂閱管線事件
context.AuthenticateRequest += OnAuthenticateRequest;
context.BeginRequest += OnBeginRequest;
context.EndRequest += OnEndRequest;
}
private void OnAuthenticateRequest(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
// 自訂驗證邏輯:檢查 Token、Cookie、Header 等
if (!IsValidRequest(app.Request))
{
app.Response.StatusCode = 401;
app.CompleteRequest(); // 短路管線,直接結束請求
}
}
private void OnBeginRequest(object sender, EventArgs e)
{
// 記錄請求資訊、URL 重寫、IP 封鎖等
}
public void Dispose() { /* 清理資源 */ }
}
註冊於 web.config(IIS 7+ 整合模式請用 <system.webServer>):
<system.webServer>
<modules>
<add name="CustomAuthModule" type="MyProject.CustomAuthModule, MyProject" />
</modules>
</system.webServer>
BeginRequest 或 PostMapRequestHandler 修改 Context.RewritePath()。PostRequestHandlerExecute 檢查 Accept-Encoding 標頭,包裝 Response.Filter。Error 事件記錄日誌、導向友善錯誤頁。BeginRequest/EndRequest 計算耗時、記錄慢查詢。掌握 ASP.NET 管線事件順序,善用 HttpHandler 處理特定資源型別、HttpModule 實作橫切關注點,是打造可維護、高擴充性 Web 應用的關鍵。下次面對跨頁面共用邏輯時,請優先考慮模組化方案,而非在每個頁面重複撰寫程式碼。