Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

[API예외] HandlerExceptionResolver 본문

인프런/[인프런] 스프링 MVC 2

[API예외] HandlerExceptionResolver

Seung__ 2021. 9. 28. 21:45
  • 예외가 발생해서 서블릿을 넘어 WAS까지 예외가 전달되면 
  • HTTP 상태코드가 500으로 처리된다.
  • 발생하는 예외에 따라서 400, 404 등등 다른 상태코드로 처리하고 싶은데?
  • 오류 메시지, 형식등을 API마다 다르게 처리하고 싶다.??
  • 예를들어 IllegalArgumentException이 controller 밖으로 넘어가면???400으로 처리하고 싶음!
    • 400 : Client가 범인임!

 

 

1. ApiExceptionController


  • "/api/members/bad"로 넘어오면 IllegalArgumentException을 던지자.
 @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);
    }
  • 하지만 WAS 입장에서는 Server에서 예외가 발생해서 WAS까지 왔으니 500이다.

 

 

2. HandlerExceptionResolver


  • 스프링 MVC는 컨트롤러(핸들러) 밖으로 예외가 던져진 경우 
  • 예외를 해결하고, 동작을 새로 정의할 수 있는 방법을 제공.
  • 컨트롤러 밖으로 던져진 예외를 해결하고, 동작 방식을 변경하고 싶으면
    HandlerExceptionResolver 를 사용하면 된다. 줄여서 ExceptionResolver

 

2.1 ExceptionResolver 적용 전


 

 

2.2 ExceptionResolver 적용 후


  • 마찬가지로 예외터지면  postHAndle은 호출 안함.
  • 대신에 ExceptionResolver가 있으면 호출함.
  • 여기서 예외 처리가 되면 정상응답으로 나감.
    • WAS 가  500으로 던지지 않고, 개발자가 정의한 로직으로 처리 가능?

 

 

 

3. HandlerExceptionResolver 인터페이스


  • handler : 핸들러(컨트롤러) 정보
  • Exception ex : 핸들러(컨트롤러)에서 발생한 발생한 예외
  • 해당 인터페이스를 구현하면 예외 발생 시 원하는 로직으로 처리 가능.
public interface HandlerExceptionResolver {
  ModelAndView resolveException(
  	HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex);
}

 

 

 

4. MyHandlerExceptionResolver


  • HandlerExceptionResolver를 구현해보자.
  • IllegalArgumentException이 넘어온 경우 HttpServletReponse에 상태코드를 400(Bad Request)로 지정!
  • ModelAndView를 새로 만들어서 return 한다.
  • ModelAndView 를 반환하는 이유는 마치 try, catch를 하듯이,
  • Exception 을 처리해서 정상 흐름 처럼 변경하는 것이 목적!!!
  • 발생한 예외를 먹어버리고, 정상적인 것 처럼 ModelAndView를 반환.
  • Servlet은 빈 model, View를 받는다. 뿌릴 view가 없다 ㅋㅋ
  • WAS는 response를 보고 senError가 호출되었는지 확인.
  • 이 때 400이구나!!! 이에 맞는 로직으로 처리함.
  • 기존처럼 예외발생 시 500으로 처리하지 않음.
@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 to 400");
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage());
                return new ModelAndView();
                //예외를 먹어버리고, 빈 ModelAndView를 반환하면 정상처리 가능.
                //return return -> Servlet까지 올라감.
                //WAS는 sendError 호출했는지 봤는데 400이네? 이에 해당하는 로직 처리함.
            }
        }catch (IOException e){
            log.error("resolver ex", e);
        }
        //null을 return 하면 터진 예외가 쭈욱 올라감.
        return null;
    }
}

 

 

 

5. HandlerExceptionResolver 등록


  • extendHandlerExceptionResolvers() 사용
  • configureHandlerExceptionResolvers(..) 를 사용하면 스프링이 기본으로 등록하는
    ExceptionResolver 가 제거되므로 주의, extendHandlerExceptionResolvers 를 사용하자.
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {

        resolvers.add(new MyHandlerExceptionResolver());
    }

}

 

 

6. 반환 값에 따른 동작 방식


  • HandlerExceptionResolver 의 반환 값에 따른 DispatcherServlet 의 동작 방식이 달라진다.
  • 빈 ModelAndView: new ModelAndView() 처럼 빈 ModelAndView 를 반환하면 
    • 뷰를 렌더링 하지않고, 정상 흐름으로 서블릿이 리턴된다.
  • ModelAndView 지정: ModelAndView 에 View , Model 등의 정보를 지정해서 반환하면 뷰를 렌더링
  • null: null 을 반환하면, 다음 ExceptionResolver 를 찾아서 실행한다. Exception이 그대로 넘어감. 
    • 만약 처리할 수 있는ExceptionResolver 가 없으면 예외 처리가 안되고, 
    • 기존에 발생한 예외를 서블릿 밖으로 던진다. -> WAS는 500으로 처리함.

 

 

7. ExceptionResolver 활용


  • 예외 상태 코드 변환
    • 예외를 response.sendError(xxx) 호출로 변경해서
    • 서블릿에서 상태 코드에 따른 오류를 처리하도록 위임
    • 이후 WAS는 서블릿 오류 페이지를 찾아서 내부 호출,
    • 예를 들어서 스프링 부트가 기본으로 설정한 /error 가 호출됨
  • 뷰 템플릿 처리
    • ModelAndView 에 값을 채워서 예외에 따른 새로운 오류 화면 뷰 렌더링
  • API 응답 처리
    • response.getWriter().println("hello"); 처럼 
    • HTTP 응답 바디에 직접 데이터를 넣어주는 것도 가능하다. 
    • 여기에 JSON 으로 응답하면 API 응답 처리를 할 수 있다.

 

8. GitHub : 210928 HandlerExceptionResolver


 

GitHub - bsh6463/Exception

Contribute to bsh6463/Exception development by creating an account on GitHub.

github.com

 

Comments