using System.Net;
using System.Text.Json;
namespace CodePlay.WebAPI.Middleware;
///
/// 全局异常处理中间件
///
public class GlobalExceptionHandler
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public GlobalExceptionHandler(RequestDelegate next, ILogger 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)
{
var response = context.Response;
response.ContentType = "application/json";
var errorResponse = new ErrorResponse
{
RequestId = context.TraceIdentifier,
Timestamp = DateTime.UtcNow,
Path = context.Request.Path,
Method = context.Request.Method
};
switch (exception)
{
case UnauthorizedAccessException:
response.StatusCode = (int)HttpStatusCode.Unauthorized;
errorResponse.Code = "UNAUTHORIZED";
errorResponse.Message = "未授权访问";
_logger.LogWarning(exception, "未授权访问尝试");
break;
case ArgumentException argumentEx:
response.StatusCode = (int)HttpStatusCode.BadRequest;
errorResponse.Code = "BAD_REQUEST";
errorResponse.Message = argumentEx.Message;
_logger.LogWarning(exception, "参数验证失败");
break;
case KeyNotFoundException:
response.StatusCode = (int)HttpStatusCode.NotFound;
errorResponse.Code = "NOT_FOUND";
errorResponse.Message = "资源不存在";
_logger.LogWarning(exception, "资源未找到");
break;
case InvalidOperationException invalidEx:
response.StatusCode = (int)HttpStatusCode.Conflict;
errorResponse.Code = "CONFLICT";
errorResponse.Message = invalidEx.Message;
_logger.LogWarning(exception, "操作无效");
break;
case TimeoutException:
response.StatusCode = (int)HttpStatusCode.GatewayTimeout;
errorResponse.Code = "TIMEOUT";
errorResponse.Message = "请求超时";
_logger.LogError(exception, "请求超时");
break;
default:
response.StatusCode = (int)HttpStatusCode.InternalServerError;
errorResponse.Code = "INTERNAL_ERROR";
errorResponse.Message = "服务器内部错误";
_logger.LogError(exception, "未处理的异常");
break;
}
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
var jsonResponse = JsonSerializer.Serialize(errorResponse, options);
await response.WriteAsync(jsonResponse);
}
}
///
/// 错误响应模型
///
public class ErrorResponse
{
public string RequestId { get; set; } = "";
public DateTime Timestamp { get; set; }
public string Code { get; set; } = "";
public string Message { get; set; } = "";
public string Path { get; set; } = "";
public string Method { get; set; } = "";
public Dictionary? Details { get; set; }
}
///
/// 中间件扩展
///
public static class GlobalExceptionHandlerExtensions
{
public static IApplicationBuilder UseGlobalExceptionHandler(this IApplicationBuilder app)
{
return app.UseMiddleware();
}
}