在 Global.asax 的 Application_Error 事件中攔截未處理的例外,針對 HTTP 404 (找不到頁面) 導向友善的自訂錯誤頁面,其他錯誤導向通用錯誤頁或記錄日誌。
void Application_Error(object sender, EventArgs e)
{
// 1. 取得目前 HttpContext 與最後發生的例外
HttpContext ctx = HttpContext.Current;
Exception ex = ctx.Server.GetLastError();
// 2. 嘗試轉型為 HttpException (含 HTTP 狀態碼)
HttpException httpEx = ex as HttpException;
if (httpEx != null)
{
int httpCode = httpEx.GetHttpCode();
// 3. 專門處理 404
if (httpCode == 404)
{
// 清除錯誤狀態,避免觸發 customErrors 再次導向
ctx.ClearError();
// 導向自訂 404 頁面 (false = 不終止執行緒,讓 Response 完成)
ctx.Response.Redirect("~/NotFound.aspx", false);
// 確保後續程式碼不執行
ctx.Response.End();
return;
}
}
// 4. 非 404 錯誤:導向通用錯誤頁或記錄日誌
// 這裡使用 Server.Transfer 保持原始 URL (方便記錄/除錯)
ctx.Server.Transfer("~/Error.aspx", false);
}
| 方法/屬性 | 用途 |
|---|---|
| ctx.Server.GetLastError() | 取得導致錯誤的原始例外物件 |
| HttpException.GetHttpCode() | 取得 HTTP 狀態碼 (404, 500, 403...) |
| ctx.ClearError() | 清除錯誤狀態,防止 ASP.NET 預設錯誤處理流程介入 |
| Response.Redirect(url, false) | 導向新頁面,false 表示不呼叫 Response.End() (避免 ThreadAbortException) |
| Response.End() | 立即結束回應,確保不再執行後續程式碼 |
| Server.Transfer(url, false) | 伺服器端轉交,URL 不變,保持原始請求資訊 |
雖然 Application_Error 可完全掌控,但建議保留 customErrors 作為第二層防線:
<system.web>
<customErrors mode="RemoteOnly" defaultRedirect="~/Error.aspx">
<error statusCode="404" redirect="~/NotFound.aspx" />
<error statusCode="500" redirect="~/ServerError.aspx" />
</customErrors>
</system.web>
mode="RemoteOnly":本機開發顯示詳細錯誤 (黃色死機畫面),遠端使用者看自訂頁面。Application_Error 優先順序高於 customErrors,故需呼叫 ClearError() 避免衝突。<%@ Page Language="C#" %>
<html><head><title>頁面不存在</title></head><body>
<div style="text-align:center; padding:50px;">
<h1>404 - 找不到頁面</h1>
<p>您請求的頁面可能已移除、更名或暫時無法使用。</p>
<p>
<a href="/">返回首頁</a> |
<a href="javascript:history.back()">上一頁</a> |
<a href="/SiteMap.aspx">網站地圖</a>
</p>
</div>
</body></html>
if (httpCode == 404)
{
// 記錄至資料庫/日誌
string requestedUrl = ctx.Request.Url.ToString();
string referrer = ctx.Request.UrlReferrer?.ToString() ?? "無";
string userAgent = ctx.Request.UserAgent;
string userIp = ctx.Request.UserHostAddress;
Log404(requestedUrl, referrer, userAgent, userIp); // 自訂記錄方法
ctx.ClearError();
ctx.Response.Redirect("~/NotFound.aspx", false);
ctx.Response.End();
}
app.UseStatusCodePagesWithReExecute("/Error/{0}") 中介軟體取代 Global.asax。