.NET Core API统一错误处理中间件实现指南

发布时间:2026/7/19 6:41:33
.NET Core API统一错误处理中间件实现指南 1. 项目概述在.NET Core API开发中错误处理是一个关键环节。统一的错误拦截机制能够帮助我们标准化错误响应格式集中处理异常逻辑提供一致的客户端体验简化调试和问题排查2. 核心需求解析2.1 为什么需要统一错误处理当API接口出现异常时我们需要确保客户端收到结构化的错误信息敏感信息不会泄露错误日志被完整记录HTTP状态码准确反映问题性质2.2 常见错误场景典型的API错误包括业务逻辑异常数据验证失败资源未找到权限不足系统内部错误3. 技术实现方案3.1 中间件实现创建全局异常处理中间件public class ExceptionHandlingMiddleware { private readonly RequestDelegate _next; private readonly ILoggerExceptionHandlingMiddleware _logger; public ExceptionHandlingMiddleware( RequestDelegate next, ILoggerExceptionHandlingMiddleware logger) { _next next; _logger logger; } public async Task InvokeAsync(HttpContext context) { try { await _next(context); } catch (Exception ex) { await HandleExceptionAsync(context, ex); } } private async Task HandleExceptionAsync(HttpContext context, Exception exception) { _logger.LogError(exception, An unexpected error occurred); var response new ErrorResponse { StatusCode GetStatusCode(exception), Message GetMessage(exception), Details context.Request.Path }; context.Response.ContentType application/json; context.Response.StatusCode response.StatusCode; await context.Response.WriteAsync(JsonSerializer.Serialize(response)); } private static int GetStatusCode(Exception exception) exception switch { ValidationException StatusCodes.Status400BadRequest, NotFoundException StatusCodes.Status404NotFound, UnauthorizedAccessException StatusCodes.Status401Unauthorized, _ StatusCodes.Status500InternalServerError }; }3.2 注册中间件在Startup.cs中配置public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseMiddlewareExceptionHandlingMiddleware(); // 其他中间件... }4. 进阶实现技巧4.1 使用ProblemDetails规范遵循RFC 7807标准services.AddProblemDetails(options { options.CustomizeProblemDetails ctx { ctx.ProblemDetails.Extensions.Add(requestId, ctx.HttpContext.TraceIdentifier); }; });4.2 验证错误处理处理ModelState验证错误services.ConfigureApiBehaviorOptions(options { options.InvalidModelStateResponseFactory context { var problemDetails new ValidationProblemDetails(context.ModelState) { Type https://tools.ietf.org/html/rfc7231#section-6.5.1, Title Validation Error, Status StatusCodes.Status400BadRequest, Instance context.HttpContext.Request.Path }; return new BadRequestObjectResult(problemDetails); }; });5. 生产环境最佳实践5.1 安全考虑确保生产环境中不暴露堆栈跟踪不泄露敏感信息使用标准错误格式记录完整错误日志5.2 性能优化错误处理中的性能要点避免在热路径中进行复杂处理使用缓存常见错误响应异步日志记录限制错误详情大小6. 测试与验证6.1 单元测试示例测试中间件行为[Fact] public async Task ShouldReturnProperErrorResponse() { // Arrange var middleware new ExceptionHandlingMiddleware( innerHttpContext throw new ValidationException(Invalid input), Mock.OfILoggerExceptionHandlingMiddleware()); var context new DefaultHttpContext(); context.Response.Body new MemoryStream(); // Act await middleware.InvokeAsync(context); // Assert context.Response.Body.Seek(0, SeekOrigin.Begin); var reader new StreamReader(context.Response.Body); var response await reader.ReadToEndAsync(); Assert.Equal(StatusCodes.Status400BadRequest, context.Response.StatusCode); Assert.Contains(Invalid input, response); }6.2 集成测试测试完整请求流程[Fact] public async Task ApiEndpoint_ReturnsFormattedError() { // Arrange var factory new WebApplicationFactoryStartup(); var client factory.CreateClient(); // Act var response await client.GetAsync(/api/test/throw); // Assert Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); var content await response.Content.ReadAsStringAsync(); var error JsonSerializer.DeserializeErrorResponse(content); Assert.NotNull(error); Assert.Equal(500, error.StatusCode); }7. 常见问题解决7.1 错误信息不统一解决方案创建基础异常类使用异常过滤器实现自定义ProblemDetailsFactory7.2 日志记录不完整推荐做法记录请求上下文包含用户信息保存相关ID如CorrelationId结构化日志格式8. 性能考量错误处理对性能的影响主要来自异常创建和捕获开销日志记录I/O响应序列化中间件管道处理优化建议避免过度使用异常处理业务逻辑异步记录日志缓存常见错误响应限制错误详情数据量9. 扩展方案9.1 分布式追踪集成结合OpenTelemetryservices.AddOpenTelemetry() .WithTracing(builder builder .AddAspNetCoreInstrumentation() .AddConsoleExporter());9.2 客户端错误处理提供客户端SDK处理建议// 前端错误处理示例 async function callApi() { try { const response await fetch(/api/data); if (!response.ok) { const error await response.json(); handleApiError(error); return; } // 处理正常响应 } catch (error) { handleNetworkError(error); } } function handleApiError(error) { if (error.statusCode 401) { // 跳转登录 } else if (error.statusCode 429) { // 重试逻辑 } else { // 显示通用错误 } }10. 部署注意事项生产环境部署时需要禁用开发人员异常页配置适当的日志级别设置全局错误路由监控错误率指标配置告警阈值典型生产配置public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler(/error); app.UseHsts(); } app.UseMiddlewareExceptionHandlingMiddleware(); }