ASP.NET Core 中用 UseExceptionHandler
捕获未处理异常
ASP.NET Core 不再支持传统的
Global.asax或
Application_Error,全局异常必须在中间件管道中注册。最标准的做法是调用
UseExceptionHandler,它会拦截所有未被
try/catch捕获的异常,并重定向到指定的错误处理路径(如
/error)或直接返回响应。
关键点:
UseExceptionHandler必须放在
UseRouting之后、
UseEndpoints之前,否则无法生效 它只捕获 HTTP 请求生命周期内的异常,不处理后台任务(如
HostedService)或应用启动阶段的异常 默认返回状态码 500,但响应体内容可自定义(JSON、HTML 或纯文本)
app.UseExceptionHandler("/error"); // 重定向到控制器路由
// 或
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = "application/json";
var ex = context.Features.Get<IExceptionHandlerFeature>()?.Error;
await context.Response.WriteAsJsonAsync(new { error = ex?.Message });
});
});
在 /error
控制器里获取原始异常信息
使用路径方式(如
/error)时,需确保对应控制器能从
IExceptionHandlerFeature中提取异常详情。这个 Feature 只在
UseExceptionHandler("/error") 触发的请求中存在,普通请求里取不到。
常见疏漏:
忘记添加[Route("error")] 或路由匹配失败,导致进不了该 Action
直接读 HttpContext.Request.Query或
Body试图找异常 —— 错,必须用
context.Features.Get<iexceptionhandlerfeature>()</iexceptionhandlerfeature>没检查
Feature?.Error是否为 null,导致空引用异常
[Route("error")]
public class ErrorController : ControllerBase
{
[HttpGet]
public IActionResult HandleError()
{
var feature = HttpContext.Features.Get<IExceptionHandlerFeature>();
var ex = feature?.Error;
if (ex == null) return Problem("Unknown error", statusCode: 500);
// 生产环境避免暴露堆栈,开发环境可加
var response = new { message = ex.Message, stack = Environment.IsDevelopment() ? ex.StackTrace : null };
return Problem(detail: ex.Message, statusCode: 500);
}
}
如何区分开发/生产环境并控制错误输出粒度
直接把
Exception.StackTrace或
InnerException返回给前端,在生产环境属于严重安全风险。ASP.NET Core 提供了
Environment.IsDevelopment()和内置的
ProblemDetails标准化结构,应配合使用。
建议做法:
开发环境:返回完整StackTrace+
InnerException,便于调试 生产环境:仅返回泛化错误消息(如 "An unexpected error occurred"),日志记录完整异常 避免在 JSON 响应中拼接
ex.ToString(),它包含敏感类型名和路径
日志记录必须独立做,不能依赖
UseExceptionHandler的响应逻辑。推荐在
HandleError方法开头就调用
_logger.LogError(ex, "Unhandled exception")。
全局异常处理不覆盖的三种典型场景
UseExceptionHandler很强大,但不是万能的。以下三类异常它完全捕获不到,必须单独处理:
Startup.ConfigureServices阶段抛出的异常 —— 应用根本起不来,需靠宿主日志(如 Windows Event Log 或
dotnet run控制台输出)排查 后台服务(
IHostedService)中未捕获的异常 —— 这些运行在独立线程,需在
ExecuteAsync内自行
try/catch并记录 终结点路由前的异常(如
UseHttpsRedirection中证书验证失败)—— 发生在中间件链更早位置,可能绕过
UseExceptionHandler
尤其要注意 HTTPS 重定向失败时,浏览器可能直接显示“连接被重置”,而服务端日志里没有任何异常记录 —— 这类问题得查
Kestrel日志级别或启用
Microsoft.AspNetCore.Server.Kestrel的 Debug 级别日志。
