ASP.NET Core 8.0 Web API全局异常处理统一响应方案问询
ASP.NET Core 8.0 Web API全局统一异常处理方案
问题背景
我正在构建ASP.NET Core 8.0 Web API,需要实现全局异常处理,确保应用中任何位置的异常都返回一致格式的JSON响应。当前不同错误场景的响应格式不一致:
- 自定义业务逻辑异常返回:
{ "message": "User not found" }
- 模型验证错误返回:
{ "errors": { "Email": ["Email is required"] } }
- 未处理异常(500错误)在生产环境仅返回通用错误页或空响应。
期望的统一响应格式
所有错误都需要返回如下结构的JSON:
{ "statusCode": 404, "message": "User not found", "details": "Additional context here" }
已尝试的方案及问题
- 自定义异常中间件
代码实现:
public class ExceptionMiddleware { private readonly RequestDelegate _next; public ExceptionMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { try { await _next(context); } catch (Exception ex) { await HandleExceptionAsync(context, ex); } } private static Task HandleExceptionAsync(HttpContext context, Exception exception) { context.Response.ContentType = "application/json"; context.Response.StatusCode = StatusCodes.Status500InternalServerError; var response = new { statusCode = context.Response.StatusCode, message = exception.Message }; return context.Response.WriteAsJsonAsync(response); } }
注册方式:
app.UseMiddleware<ExceptionMiddleware>();
问题:仅能捕获未处理异常,无法处理模型绑定验证错误或过滤器中抛出的异常。
- 内置
UseExceptionHandler
代码实现:
app.UseExceptionHandler("/error"); app.Map("/error", (HttpContext context) => { var exception = context.Features.Get<IExceptionHandlerFeature>()?.Error; return Results.Problem(title: exception?.Message); });
问题:返回默认ProblemDetails格式,不符合自定义需求,且无法捕获验证错误。
解决方案
1. 捕获所有错误的推荐方案
在ASP.NET Core 8.0 Web API中,要覆盖未处理异常、验证错误、自定义异常所有场景,需要组合两种核心方式:
- 自定义异常中间件(处理管道中绝大多数同步/异步未捕获异常)
- 配置
ApiBehaviorOptions(替换默认的模型验证错误响应格式)
2. 中间件、过滤器还是UseExceptionHandler?
- 中间件:优先级最高,能捕获路由匹配、过滤器、Action执行等全管道环节的异常,是全局异常处理的核心载体。
- 异常过滤器:仅能捕获Action执行过程(含模型绑定后、ActionFilter内)的异常,无法覆盖路由、中间件层级的错误,仅适合作为补充场景使用。
UseExceptionHandler:内置方案但定制化能力弱,默认返回ProblemDetails格式,不适合需要完全自定义响应结构的场景。
综上,推荐以自定义中间件为主,配合ApiBehaviorOptions处理验证错误。
3. 统一验证错误的响应格式
通过配置ApiBehaviorOptions替换默认的验证错误生成逻辑:
builder.Services.Configure<ApiBehaviorOptions>(options => { options.InvalidModelStateResponseFactory = context => { // 收集所有验证错误并拼接为详情文本 var errorDetails = string.Join("; ", context.ModelState .Where(e => e.Value.Errors.Any()) .SelectMany(kv => kv.Value.Errors.Select(err => err.ErrorMessage)) ); var response = new { statusCode = StatusCodes.Status400BadRequest, message = "Validation failed", details = errorDetails }; return new BadRequestObjectResult(response); }; });
4. 区分不同异常类型返回对应状态码
先定义业务相关的自定义异常(示例):
public class NotFoundException : Exception { public NotFoundException(string message) : base(message) { } } public class ValidationException : Exception { public ValidationException(string message) : base(message) { } }
然后扩展中间件的异常处理逻辑,根据异常类型映射HTTP状态码:
private static Task HandleExceptionAsync(HttpContext context, Exception exception) { context.Response.ContentType = "application/json"; // 根据异常类型匹配响应信息 var errorInfo = exception switch { NotFoundException notFoundEx => ( StatusCode: StatusCodes.Status404NotFound, Message: notFoundEx.Message, Details: "Requested resource does not exist" ), ValidationException validationEx => ( StatusCode: StatusCodes.Status400BadRequest, Message: validationEx.Message, Details: "Input data validation failed" ), _ => ( StatusCode: StatusCodes.Status500InternalServerError, Message: "An unexpected error occurred", Details: #if DEBUG exception.ToString() // 开发环境返回完整异常栈 #else "Internal server error" // 生产环境隐藏敏感信息 #endif ) }; context.Response.StatusCode = errorInfo.StatusCode; var response = new { statusCode = errorInfo.StatusCode, message = errorInfo.Message, details = errorInfo.Details }; return context.Response.WriteAsJsonAsync(response); }
最终Program.cs配置示例
注意中间件注册顺序:需放在UseRouting()之后、UseAuthorization()之前:
var builder = WebApplication.CreateBuilder(args); // 添加控制器服务 builder.Services.AddControllers(); // 配置验证错误响应格式 builder.Services.Configure<ApiBehaviorOptions>(options => { options.InvalidModelStateResponseFactory = context => { var errorDetails = string.Join("; ", context.ModelState .Where(e => e.Value.Errors.Any()) .SelectMany(kv => kv.Value.Errors.Select(err => err.ErrorMessage)) ); var response = new { statusCode = StatusCodes.Status400BadRequest, message = "Validation failed", details = errorDetails }; return new BadRequestObjectResult(response); }; }); var app = builder.Build(); // 注册自定义异常中间件 app.UseMiddleware<ExceptionMiddleware>(); app.UseAuthorization(); app.MapControllers(); app.Run();
内容的提问来源于stack exchange,提问作者Pourya Ziamanesh
相关产品推荐
相关产品推荐

