API예외 - HandlerExceptionResolver

바그다드·2023년 5월 24일
0

예외

목록 보기
5/9
  • HTML예외 처리를 생각해보자. 로그인 기능의 문제이든, 게시판 업로드 기능의 문제이든 HTML 예외 처리의 경우 4XX, 5XX의 경우만 생각하고, 그에 맞는 예외 페이지만 띄워주면 된다.
    하지만 API의 경우는?
    API의 경우 HTML문서를 반환하는 것이 아니라, 각 기능에 따라서 어떤 부분이 문제가 있는지에 대한 정보를 반환해야 하기 때문에 기능별로 다른 응답을 해야하는 문제가 생긴다. 그 방법에 대해 알아보자.

HandlerExceptionResolver

기존에 했던 방법은 예외가 발생해서 WAS까지 전달될 경우에 예외의 종류에 상관없이 500 에러가 발생하였다. 이제 예외에 따라 400, 404등 다른 에러로 처리를 해보자.

컨트롤러

    @GetMapping("/api/members/{id}")
    public MemberDto getMember(@PathVariable("id") String id) {

        if (id.equals("ex")) {
            throw new RuntimeException("잘못된 사용자");
        }

        if (id.equals("bad")) {
            throw new IllegalArgumentException("잘못된 입력 값");
        }

        return new MemberDto(id, "hello" + id);
    }
  • 기존의 메서드에 id값이 bad일 경우 IllegalArgumentException을 발생시키는 코드를 추가하였다. 결과를 확인해보면

    마찬가지로 500에러가 발생하는 것을 확인할 수 있다. 당연하다. 하지만 생각해보면 id의 값으로 bad를 넘기지 않기로 약속되어 있는데 클라이언트에서 bad라는 값을 넘겨 에러가 발생한 것이므로 4xx에러가 발생해야 한다.
  • HandlerExceptionResolver(줄여서 ExceptionResolver 라고도 한다.)를 활용하면 컨트롤러(핸들러) 밖으로 던져진 예외를 해결하고, 동작 방식을 변경할 수 있다.

ExceptionResolver 적용시 흐름


1. 인터셉터 preHandle 수행
2. 핸들러 실행
3. 예외 발생
4. Dispatcher Servlet으로 예외 전달
5. ExceptionResolver가 예외 해결 시도
ModelAndView반환
6. (정상 호출 시) view 반환
7. (예외 발생 시) afterCompletion 수행
8. 정상 응답

  • 글로만 확인해서는 잘 감이 잡히지 않으니 코드로 확인해보자.

ExceptionResolver생성

@Slf4j
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        try {
            if (ex instanceof IllegalArgumentException) {
                log.info("IllegalArgumentException resolver");
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
                return new ModelAndView();
            }
        } catch (IOException e) {
            log.error("resolver ex", e);
        }

        return null;
    }
}
  • HandlerExceptionResolver를 상속받아 메서드를 override하자.
    리턴 타입이 ModelAndView인 것을 확인할 수 있다.
  • ModelAndView를 반환하기 때문에 그 이후의 과정이 정상적으로 처리되고, WAS에서는 500에러가 아닌 response에 설정했던 400에러가 발생하게 된다.
  • 해당 코드에서 ModelAndView에는 아무러 값이 들어있지 않기 때문에 뷰를 렌더링하지 않고, 정상 흐름으로 서블릿이 리턴 된다.
    ModelAndView에 Model, View 등의 데이터를 포함하면 뷰를 렌더링 한다.
    null을 반환할 경우 다음 ExceptionResolver를 실행시키는데, 다른 ExceptionResolver에서도 예외가 처리되지 않을 경우, 기존에 발생한 예외가 WAS로 전달되고, 500에러가 발생하게 된다.

이제 ExceptionResolver를 등록해주자

ExceptionResolver 등록

@Configuration
public class WebConfig implements WebMvcConfigurer {

	// 생략
    
    // HandlerExceptionResolver 추가
    @Override
    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        resolvers.add(new MyHandlerExceptionResolver());
    }
    
    // 생략
  • 해당 설정에서는 extendHandlerExceptionResolvers를 오버라이드 하고 있는데 이 메서드는 스프링 기본 ExceptionResolver에 내가 생성한 ExceptionResolver를 추가하는 메서드다.

  • configureHandlerExceptionResolvers를 오버라이드할 경우 스프링 기본 ExceptionResolver가 제거되므로 주의하자!!!

  • 이제 다시 결과를 확인해보면

    400에러가 발생한 것을 확인할 수 있다!!!

  • 이걸로 기본적인 ExceptionResolver 사용법에 대해서 알아보았다. 다름 포스팅에서는 ExceptionResolver의 활용 방법에 대해서 알아보자!!!

출처 : 김영한 스프링MVC2편

profile
꾸준히 하자!

0개의 댓글