using Microsoft.Data.SqlClient; namespace OASystem.API.Middlewares { /// /// 全局异常捕获中间件 /// public class ExceptionHandlingMiddleware { private readonly RequestDelegate _next; // 用来处理上下文请求 private readonly ILogger _logger; private readonly SqlSugarClient _db; /// /// 初始化 /// /// /// /// public ExceptionHandlingMiddleware(RequestDelegate next, ILogger logger, SqlSugarClient db) { _next = next; _logger = logger; _db = db; } /// /// 执行中间件 /// /// /// /// public async Task InvokeAsync(HttpContext httpContext, SqlSugarClient db) { try { await _next(httpContext); //要么在中间件中处理,要么被传递到下一个中间件中去 } catch (Exception ex) { await HandleExceptionAsync(httpContext, ex, db); // 捕获异常了 在HandleExceptionAsync中处理 } } /// /// 自定义全局异常处理方法 /// /// /// /// /// private async Task HandleExceptionAsync(HttpContext context, Exception exception, SqlSugarClient db) { if (db.Ado != null && db.Ado.Transaction != null) { try { db.Ado.RollbackTran(); } catch (Exception ex) { _logger.LogError("Error rolling back transaction: {ErrorMessage}", ex.Message); } } // 检查响应是否已开始 if (!context.Response.HasStarted) { context.Response.ContentType = "application/json"; // 设置响应内容类型为 JSON var response = context.Response; var errorResponse = new JsonView { Code = StatusCodes.Status500InternalServerError, Data = "" }; // 根据异常类型设置不同的响应状态码和消息 switch (exception) { case SqlException sqlEx when sqlEx.Number == -2: response.StatusCode = StatusCodes.Status503ServiceUnavailable; errorResponse.Msg = "数据库连接超时,请稍后重试。"; break; case SqlException sqlEx when sqlEx.Number == -4: response.StatusCode = StatusCodes.Status503ServiceUnavailable; errorResponse.Msg = "数据库连接池耗尽,请稍后重试。"; break; case ApplicationException ex when ex.Message.Contains("Invalid token"): response.StatusCode = StatusCodes.Status403Forbidden; errorResponse.Msg = ex.Message; break; case ApplicationException ex: response.StatusCode = StatusCodes.Status400BadRequest; errorResponse.Msg = ex.Message; break; case KeyNotFoundException ex: response.StatusCode = StatusCodes.Status404NotFound; errorResponse.Msg = ex.Message; break; case SqlSugarException ex: response.StatusCode = ex.Message.Contains("timeout") ? StatusCodes.Status503ServiceUnavailable : StatusCodes.Status500InternalServerError; errorResponse.Msg = ex.Message.Contains("timeout") ? "数据库连接超时,请稍后重试。" : ex.Message; break; default: response.StatusCode = StatusCodes.Status500InternalServerError; errorResponse.Msg = "服务器内部错误"; // 不直接暴露异常详细信息 break; } _logger.LogError(exception, "An exception occurred."); // 记录异常详细信息 var result = JsonConvert.SerializeObject(errorResponse); await context.Response.WriteAsync(result); // 将错误响应写入客户端 } else { // 如果响应已开始,记录日志但不做进一步处理 _logger.LogError(exception, "An exception occurred after response started."); } } } }