본문 바로가기
Spring

[Spring] Filter에서 ExceptionHandler 예외 메시지 전달하기

by 흑시바 2023. 3. 26.

일반적인 개발 프로젝트에서는 클라이언트에게 전체 예외 메시지가 아닌 특정 형태를 갖춘 메시지를 반환한다.

 

현재 개발 중인 프로젝트에서도 @RestControllerAdvice@ExceptionHandler를 활용해서 애플리케이션 전역에서 발생하는 예외를 특정 형태로 맞춰서 클라이언트에게 반환하도록 설정되어 있었고 그동안 잘 사용하고 있었다.

[GlobalExceptionHandler]

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<Object> handleIllegalArgument(IllegalArgumentException e) {
        log.error("handleIllegalArgument ", e);

        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                .body(new ShibaErrorResponse("4001", e.getMessage()));
    }

    @RequiredArgsConstructor
    @Getter
    public static class ShibaErrorResponse {

        private final String errorCode;
        private final String message;
    }
}

 

@RestControllerAdvice(또는 @ControllerAdvice)@ExceptionHandler를 사용하면 다음과 같이 특정 예외(IllegalArgumentException 등)에 대해서 특정 형태로 손쉽게 처리할 수 있다.

(ControllerAdvice = 애플리케이션 전체에서 동일한 예외 처리를 사용할 수 있도록 해준다)

 

하지만 Spring Security에서 Filter를 추가하는 업무를 수행하던 도중 예외가 발생했는데, 특정 형태로 잡지 못하고 예외 전체가 출력되는 문제가 발견되었다. 😭

[ShibaFilter]

@Component
public class ShibaFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if(request.getRequestURI().equals("/api/shiba")) {
            throw new IllegalArgumentException("예외가 발생!");
        }
        filterChain.doFilter(request, response);
    }
}

 

필터는 특정 URI에 예외가 발생하도록 설정해서 테스트하였다.

 

 

예외가 원하는 특정 형태로 반환되지 않고 그대로 출력되는 것을 확인할 수 있었다.

[원인]

그러면 원인은 대체 뭘까? 🙀

 

원인은 ControllerAdvice 적용 범위에 있었다. ControllerAdvice는 Dispatcher Servlet 내에서 발생하는 예외만 잡는다. 하지만 Filter에서 예외가 발생하면 시점이 Dispatcher Servlet 처리 이전이므로 특정 형태로 처리가 불가능하다.

 

[해결]

기존 애플리케이션의 예외 처리와 동일한 특정 예외 처리 형태를 유지하려면 Controller까지 보내서(위임해서) 예외를 처리하면 된다. 즉, Spring에서 예외를 처리하는 방법 중 한 가지인 HandlerExceptionResolver에게 예외를 위임한다.

 

@Component
public class ShibaFilter extends OncePerRequestFilter {

    private final HandlerExceptionResolver resolver;

    public ShibaFilter(@Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver) {
        this.resolver = resolver;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        if (request.getRequestURI().equals("/api/shiba")) {
            try {
                throw new IllegalArgumentException("예외가 발생!");
            } catch (Exception ex) {
                resolver.resolveException(request, response, null, ex);
            }
        }
        filterChain.doFilter(request, response);
    }
}

 

@Qualifier("handlerExceptionResolver")를 활용하여 정확하게 handlerExceptionResolver를 주입해 주어야 한다. 그렇지 않으면 해당하는 Bean을 여러 개 찾았다는 오류 메시지를 볼 수 있다.

 

위의 코드와 같이 HandlerExceptionResolver의 resolveException 메서드를 통해 Filter 처리 과정에서 발생한 예외를 처리하도록 넘기면 예외가 특정 형태로 클라이언트에 반환되는 것을 확인할 수 있다.

 

 

🐕 REFERENCE

 

https://stackoverflow.com/questions/34595605/how-to-manage-exceptions-thrown-in-filters-in-spring

 

How to manage exceptions thrown in filters in Spring?

I want to use generic way to manage 5xx error codes, let's say specifically the case when the db is down across my whole spring application. I want a pretty error json instead of a stack trace. F...

stackoverflow.com

https://stackoverflow.com/questions/17715921/exception-handling-for-filter-in-spring

 

exception handling for filter in spring

I am handling exceptions in spring using @ExceptionHandler. Any exception thrown by controller is caught using method annotated with @ExceptionHandler and action is taken accordingly. To avoid writ...

stackoverflow.com

https://jaehun2841.github.io/2018/08/30/2018-08-25-spring-mvc-handle-exception/#%EB%8B%A4%EC%8B%9C-%ED%95%9C%EB%B2%88-Spring-MVC%EB%A5%BC-%EB%B3%B4%EC%9E%90-%EC%9E%90%EA%BE%B8-%EB%B3%B4%EA%B2%8C%EB%90%98%EB%84%A4

 

Spring Handle Exception | Carrey`s 기술블로그

들어가며 Spring에서 제공하는 예외처리 방법에는 유용한 방법들이 몇가지 있다. Dispatcher Servlet내에서는 몇 가지 HandleExceptionResolver를 제공하여 예외 처리를 할 수 있도록 돕고 있다. 또한 @Controller

jaehun2841.github.io

댓글