GlobalExceptionHandler.cs 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. using Microsoft.AspNetCore.Diagnostics;
  2. namespace Web.Api.Common;
  3. internal sealed class GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger) : IExceptionHandler
  4. {
  5. public async ValueTask<bool> TryHandleAsync(
  6. HttpContext httpContext,
  7. Exception exception,
  8. CancellationToken cancellationToken
  9. ) {
  10. var (statusCode, message) = exception switch
  11. {
  12. BadHttpRequestException => (StatusCodes.Status400BadRequest, "Invalid request body"),
  13. KeyNotFoundException => (StatusCodes.Status404NotFound, exception.Message),
  14. InvalidOperationException => (StatusCodes.Status400BadRequest, exception.Message),
  15. UnauthorizedAccessException => (StatusCodes.Status401Unauthorized, exception.Message),
  16. // 내부 예외 메시지(EF Core/SQL 등)가 클라이언트로 노출되지 않도록 일반 메시지로 응답. 상세는 아래 LogError 로만 기록.
  17. _ => (StatusCodes.Status500InternalServerError, "요청 처리 중 오류가 발생했습니다.")
  18. };
  19. if (statusCode == StatusCodes.Status500InternalServerError)
  20. {
  21. logger.LogError(exception, "Unhandled exception occurred");
  22. }
  23. else
  24. {
  25. logger.LogWarning(exception, "Handled exception: {Message}", exception.Message);
  26. }
  27. httpContext.Response.StatusCode = statusCode;
  28. httpContext.Response.ContentType = "application/json";
  29. await httpContext.Response.WriteAsJsonAsync(new ApiResponse
  30. {
  31. Success = false,
  32. Status = statusCode,
  33. Message = message
  34. }, cancellationToken);
  35. return true;
  36. }
  37. }