인터셉터에서 예외를 발생시켜도 exception handler가 처리할 수 있을까?

아래는 spring에서 요청의 흐름이다.

요청 → 필터 → WAS → 서블릿 → 인터셉터 → 컨트롤러 →..

예외 처리는 요청 흐름의 반대로 간다고 생각하면 된다.

WAS ← 서블릿 ← 인터셉터 ← 컨트롤러(예외 발생)

컨트롤러나 그 뒤의 계층에서 던져진 예외는 DispatcherServlet 이 일단 전달받은 뒤에 다시 서블릿 밖으로 뎐져서 서블릿 컨테이너(WAS)가 처리하게 된다. 하지만 exception resolver가 등록되어 있다면 DispatcherServlet 은 먼저 exception resolver에게 해당 예외를 처리할 수 있는지 확인하게 된다. 따라서 인터셉터에서 예외를 던져도 서블릿(dispatcher servelet)가 이를 감지하고 exception resolver를 통해 처리할 수 있다.

+ 내용 추가(2022년 1월 12일)

프로젝트 중에 또다시 해당 문제가 혼란스러워 내용을 보충한다.

🤨 @Controlleradvice는 Controller(handler)에만 적용되는거 아닌가? 근데 어떻게 Interceptor에서 발생한 예외도 처리할 수 있을까? 🤨

위 생각이 문제의 시발점이었다. 스프링 문서를 찾아 보아도 ControllerAdvice가 interceptor예외를 처리한다는 직접적인 말은 없었다. 다만 아래와 같은 말이 있었다.

On startup, RequestMappingHandlerMapping and ExceptionHandlerExceptionResolver detect controller advice beans and apply them at runtime.
Spring Framework Documentation(Controller Advice)

(❗️여기서 부터는 나의 합리적 의심(?)을 기반으로 한 내용이다. 틀린 내용일 수 있다.❗️)
어플리케이션 시작시에 controller advice에 있는 ExceptionHandler에 있는 예외 처리가 ExceptionResolver에 적용(?)된다. 이후 인턴셉터에서 발생한 예외는 Dispatcher Servlet으로 전달된 후 ExceptionResolver(ControllerAdvice에 작성한 내용이 적용된)로 전달되어 처리되어 진다.

통합 테스트에서 session 사용

로그인 → 세션에 저장된 유저 정보(USER ID)를 이용하여 유저 정보 조회 → 테스트 환경에서 세션을 어떻게 설정할까?

session = new MockHttpSession();
session.setAttribute(SessionKey.LOGIN_MEMBER, user.getId());

ResultActions resultActions = mockMvc.perform(get("/api/user")
        .session(session)
        .accept(MediaType.APPLICATION_JSON))
        .andDo(print());

테스트 환경에서 session이 필요할 경우 MockHttpSession을 이용하여 session을 생성하고 이를 MockMvcRequestBuilder의 session을 이용해 설정하면 된다.

@RequestMapping & @GetMapping

@RquestMapping: 공통 url 처리

BEFORE

@RequestMapping("/api/user")
@GetMapping(“/”)

테스트에서 GET /api/user → NOT FOUND ERROR
테스트에서 GET /api/user/ → 테스트 성공

AFTER

@RequestMapping("/api/user")
@GetMapping

테스트에서 GET /api/user → 테스트 성공
테스트에서 GET /api/user/ → 테스트 성공

ControllerAdvice & RestControllerAdvice

ControllerAdvice
등록된(?) 예외 처리를 Controller 전역에 적용

RestControllerAdvice
등록된(?) 예외 처리를 Controller 전역에 적용 + @ResponseBody(응답값 → jSON으로 변환)

참고

profile
꾸준히 나아가자 🐢

0개의 댓글