欢迎光临
我们一直在努力

还在每个控制器里写 try-catch吗?ASP.NET Core 全局异常处理指南

在 ASP.NET Core Web API 开发中,很多同学习惯在每个控制器的方法里手动写 try-catch 来处理异常。这种做法虽然简单直接,但时间一长,问题就来了:代码里到处都是重复的 try-catch,业务逻辑和错误处理混在一起,改起来费劲,测试也不方便。现代 Web 应用其实有更好的办法——全局异常处理。通过中间件(Middleware)集中捕获那些没被处理的异常,控制器就能专心做自己的事,代码也更干净、一致。


问题:控制器里的重复 try-catch

如果每个控制器都自己写 try-catch,会遇到一堆麻烦:

  • 代码大量重复:差不多的异常处理逻辑,这里写一遍那里写一遍,看着就烦;

  • 职责不清:控制器本该管业务逻辑,结果还得兼顾错误处理和记日志,乱成一团;

  • 维护成本高:哪天想改个错误响应的格式,或者加一种异常类型,得把所有控制器翻出来改一遍;

  • 响应不一致:不同人写的控制器,可能返回的 HTTP 状态码、错误格式都不一样,前端对接时一脸懵;

  • 测试不好写:业务逻辑里嵌着异常处理,单元测试很难把业务单独拎出来测①。


解决方案:全局异常中间件

自己写一个中间件,就能在请求处理的管道里统一拦住所有没被捕获的异常,控制器里完全不用写 try-catch:

public classGlobalExceptionMiddleware
{
    privatereadonly RequestDelegate _next;
    privatereadonly ILogger<GlobalExceptionMiddleware> _logger;

    public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context); // 继续往后执行
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "发生未处理的异常。");
            await HandleExceptionAsync(context, ex);
        }
    }

    private static Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = exception switch
        {
            KeyNotFoundException => StatusCodes.Status404NotFound,
            UnauthorizedAccessException => StatusCodes.Status401Unauthorized,
            _ => StatusCodes.Status500InternalServerError
        };

        var response = new
        {
            error = "服务器发生意外错误。",
            // 生产环境不要把 exception.Message 直接丢给客户端,防止泄露敏感信息
        };

        return context.Response.WriteAsJsonAsync(response);
    }
}

这个中间件在管道里捕获所有异常,记完日志后,返回一个统一格式的 JSON 错误信息,既安全又规范②。


注册中间件

在 Program.cs 里把中间件加到请求管道靠前的位置,这样它就能覆盖所有请求:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();

var app = builder.Build();
app.UseMiddleware<GlobalExceptionMiddleware>(); // 最好放在 UseRouting 之前
app.MapControllers();
app.Run();

这么一配,所有请求都会被异常处理层罩住,真正做到“一次编写,全局生效”③。


这么做的优势

  • 代码清爽:控制器里全是业务逻辑,再也看不到 try-catch;

  • 响应统一:所有错误都返回同样结构的 JSON,前端处理起来省心;

  • 好维护:想改异常处理逻辑,只改一个地方就够了;

  • 更安全:生产环境下,内部错误细节不会暴露给用户;

  • 便于监控:所有异常都统一记日志,排查问题方便多了④。


结语

在 ASP.NET Core 应用里,异常处理应该作为一个横切关注点(cross-cutting concern)来集中管理,而不是散落在各个控制器里。用全局异常中间件,不仅让代码更好读、更好改,还能确保系统出错时表现一致、安全可靠。这不只是个小技巧,更是专业级 Web API 的基本素养⑤。


参考资料

① Microsoft. Handle errors in ASP.NET Core. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling
② Andrew Lock. Creating a custom error handler middleware function in ASP.NET Core. https://andrewlock.net/creating-a-custom-error-handler-middleware-function-in-asp-net-core/
③ Microsoft. ASP.NET Core Middleware. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/middleware/
④ OWASP. Error Handling and Logging Cheat Sheet.

⑤ Martin Fowler. Separation of Concerns.

赞(0)
未经允许不得转载:171主机测评 » 还在每个控制器里写 try-catch吗?ASP.NET Core 全局异常处理指南
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址