阿杰,我来给你系统梳理一下 ASP.NET WebForms 全局异常捕获与处理的最佳实践,不只是代码,还包括架构思路和运维建议,让你在生产环境下既能完整记录异常,又能优雅提示用户。
1. 核心目标
全局异常处理主要解决三个问题:
- 拦截所有未处理异常(页面、控件、后台任务等)
- 记录日志(方便运维和问题排查)
- 友好提示用户(避免“黄屏死机”)
2. ASP.NET WebForms 全局异常处理入口
2.1 Application_Error
在 Global.asax
中定义:
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
// 记录日志
LogException(ex);
// 清除异常,避免默认错误页
Server.ClearError();
// 跳转到友好错误页
Response.Redirect("~/ErrorPage.aspx");
}
特点:
- 可以捕获绝大多数运行时异常(页面生命周期、控件事件等)
- 在请求处理流程的末端执行(HttpApplication 级别)
- 如果异常在 HttpModule 级别发生,也能捕获
2.2 Page_Error
在单个页面捕获异常:
protected void Page_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
LogException(ex);
Server.ClearError();
Response.Redirect("~/ErrorPage.aspx");
}
适合场景:
- 某个页面的异常希望自定义处理
- 对全局影响不大
2.3 自定义 HttpModule
如果你想让异常处理逻辑模块化,可写一个模块:
public class ErrorHandlingModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.Error += new EventHandler(Context_Error);
}
private void Context_Error(object sender, EventArgs e)
{
var ex = ((HttpApplication)sender).Server.GetLastError();
LogException(ex);
}
public void Dispose() { }
}
然后在 web.config
中注册:
<system.webServer>
<modules>
<add name="ErrorHandlingModule" type="Namespace.ErrorHandlingModule"/>
</modules>
</system.webServer>
3. 日志记录最佳实践
3.1 使用成熟的日志库
示例(log4net):
private static readonly ILog log = LogManager.GetLogger(typeof(Global));
private void LogException(Exception ex)
{
log.Error("未处理异常", ex);
}
3.2 记录的关键信息
- 异常类型、消息、堆栈
- 当前 URL、查询参数
- 当前用户(如果已登录)
- 客户端 IP、User-Agent
- 发生时间
4. 用户友好提示页
4.1 自定义错误页
web.config
中配置:
<customErrors mode="On" defaultRedirect="ErrorPage.aspx">
<error statusCode="404" redirect="NotFound.aspx"/>
</customErrors>
mode="On"
:始终显示自定义错误页mode="RemoteOnly"
:本地显示详细错误,远程显示错误页
4.2 防止信息泄露
- 不要在错误页显示堆栈信息
- 可提供错误编号,让用户反馈时可在日志中查找
示例:
// ErrorPage.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
string errorId = Guid.NewGuid().ToString();
lblErrorId.Text = errorId;
// 存到日志
LogErrorId(errorId, Context.Items["LastError"] as Exception);
}
5. 进阶建议
- 分级处理异常
- 业务可恢复异常:局部处理(try-catch)
- 致命异常:全局捕获并记录
- 监控与告警
- 配合邮件、短信、钉钉/企业微信机器人实时报警
- 区分开发和生产
- 开发环境:详细异常(
customErrors mode="Off"
) - 生产环境:友好提示 + 日志
- 开发环境:详细异常(
6. 一个完整的全局处理方案示例
Global.asax
:
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError().GetBaseException();
// 生成错误 ID
string errorId = Guid.NewGuid().ToString();
// 记录日志
LogManager.GetLogger("GlobalError").Error($"ErrorId: {errorId}", ex);
// 清理异常
Server.ClearError();
// 存储错误 ID(可用于错误页显示)
Context.Items["ErrorId"] = errorId;
// 跳转错误页
Response.Redirect("~/ErrorPage.aspx?eid=" + errorId);
}
ErrorPage.aspx
:
protected void Page_Load(object sender, EventArgs e)
{
string eid = Request.QueryString["eid"];
lblMessage.Text = $"系统发生错误,请联系管理员,并提供错误编号:{eid}";
}
发表回复