이지은님의 블로그
250219 - Java Spring 뉴스피드 프로젝트 구현과 트러블 슈팅: handler가 interceptor에서 HandlerMethod로 캐스팅 되지 않는 문제 본문
250219 - Java Spring 뉴스피드 프로젝트 구현과 트러블 슈팅: handler가 interceptor에서 HandlerMethod로 캐스팅 되지 않는 문제
queenriwon3 2025. 2. 19. 23:49▷ 오늘 배운 것
프로젝트를 진행하면서 제일 많이 당면했던 예외상황에 대해 트러블 슈팅을 작성해보려고 한다.
<< 목차 >>
1. interceptor에서 Handler가 handlerMethod로 캐스팅 되지 않는 문제
1) Interceptor란?
2) HandlerInterceptor 인터페이스 - preHandle
3) HandlerInterceptor에서의 handler
4) 예외처리를 해주자
1. interceptor에서 Handler가 handlerMethod로 캐스팅 되지 않는 문제
앞서 작성했던 어노테이션으로 로그인 필터링을 관리하는 interceptor를 작성해보았는데 해당 내용에서 다음과 같은 오류 상항이 생겼다.
HandlerMethod handlerMethod = (HandlerMethod) handler;
java.lang.ClassCastException: class org.springframework.web.servlet.resource.ResourceHttpRequestHandler cannot be cast to class org.springframework.web.method.HandlerMethod
이 에러의 결론은 controller에 등록된 url로 요청을 보내지 않아 발생하는 문제였다. 다음은 interceptor를 구현한 부분이다.
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
...
HandlerMethod handlerMethod = (HandlerMethod) handler;
...
}
}
이 interceptor에서 handler가 무슨 역할을 하는 것일까?
그리고 controller에서 작성한 Http Method 또는 url가 아니면, handler의 값이 null이 되는 것일까? (그동안 많은 nullpointException을 만나서...)
이를 알기 위해 interceptor란 무엇인지 알아야겠다고 생각했다.
1) Interceptor란?
Spring MVC 에서 Interceptor는 웹 애플리케이션 내에서,
특정한 Controller의 URI 호출 통해 들어오는 request와 response를 '가로채는' 역할을 한다.
filter와 같이 공통관심사, 공통로직을 사전에 처리해주는 역할을 한다.
필터는 보안과 같은 로직을, 인터셉터는 인가/인증에 관한 로직을 공통적으로 구현하고 싶을 때 주로 사용한다.
그리고 Interceptor의 경우 Spring에서 관리되기 때문에 Spring 내의 모든 객체(Bean)에 접근이 가능하다는 차이가 있다.
(그래서 filter에서 발생한 예외는 ExceptionHandler가 잡을 수 없고, interceptor에서 발생한 예외는 ExceptionHandler가 잡을 수 있다.)
이번 에러를 처리하면서 가장 핵심인 것은 이 매개변수인 handler가 무엇인지, HandlerMethod가 무엇인지 이다.
아래 이미지가 interceptor의 위치와, handler가 사용되는 위치를 파악하기 쉬울 것 같아서 참고 해보자.
핵심인 부분은 controller안에 handlerInterceptor가 있다는 것이다.
그래서 filter보다는 interceptor가 url나 HttpMethod를 파악하기 쉬웠을 것이다.
그럼 당연히 요청과 이 컨트롤러에서 정의한 메서드 대로 작성되었는지도 파악할 수 있다.
2) HandlerInterceptor 인터페이스 - preHandle
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
@Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
@Nullable Exception ex) throws Exception {
}
}
기본 인터페이스 구조이다.
- prehandle() – 실제 핸들러 실행 전에 호출됨
- postHandle() – 핸들러가 실행된 후 호출됨
- afterCompletion() – 전체 요청이 완료되고 뷰가 생성된 후 호출됨
Interceptor는 요청에 대한 가로채기(postHandle)기능도 있지만, 위 에러의 이유에 대해서 알아보기위해 preHandle을 살펴보기로 하겠다.
특히 오류의 대상이 된 prehandler의 hadler란 무엇을 뜻하는 걸까?
hadler는 현재 실행되는 Controller를 파악하거나, 추가적인 메서드를 실행하는 등의 작업을 할 수 있다.
3) HandlerInterceptor에서의 handler
잘못된 url 및 http Method를 보냈을때 디버그 모드로 handler를 추적해보자.
추적결과,
handler가 HandlerMethod가 아니라 ResponseHttpRequestHandler가 된다는 것을 알 수 있다. 그럼 당연히 HandlerMethod로 형변환을 할 수 없다.
아래는 controller layer에서 코드를 작성한 대로 올바른 url를 사용해서 요청을 보냈을 때다.
디버그 모드로 어떤 값을 가지는지 확인해보면 HandlerMethod가 매개변수로 들어왔음을 확인 할 수 있다. 이렇게 되면 HandlerMethod로 캐스팅이 가능하며,
HandlerMethod가 지원하는 메서드를 사용할 수 있다. (컨트롤러, 메서드, 매개변수 등 정보 확인 가능)
에러에 대해 정확한 이유를 알기위해 잡설이 길기는 했지만 결론은 다음과 같다.
1️⃣ interceptor는 spring의 controller 안에서 동작한다.
2️⃣ 따라서 controller에 어떤 메서드가 구현되어 있는지 확인할 수 있다.
3️⃣ controller에서 구현되지 않는 url을 사용하여 요청한다면, ResponseHttpRequestHandler가 사용된다.
4️⃣ 반대로 구현된 url로 요청한다면, HandlerMethod가 사용된다.
5️⃣ HandlerMethod는 컨트롤러, 메서드, 파라미터 등의 메서드 관련 정보를 가지고 있다.
따라서 컨트롤러에서 정의된 url 요청을 보내야 관련 에러를 마주치지 않을 수 있다.
4) 예외처리를 해주자
그럼 이 예외는 api 명세서에 있는 것과 잘못된 요청을 보냈을 때, 클라이언트… 까지는 아니겠지만, 프론트엔드가 잘못 요청을 보냈을 때 생기는 예외라는 것이다. 즉, 서버를 개발한 개발자의 잘못은 아니다.(ㅎㅎ)
따라서 500번 에러보다는 400번, bad request에러에 더 적합하지 않겠는가? 따라서 다음과 같이 try-catch를 사용하여 ClassCastException에 대한 예외를 처리해주겠다.
try {
// ClassCastException이 발생하는 곳
HandlerMethod handlerMethod = (HandlerMethod) handler;
...
} catch (ClassCastException e) {
throw new RuntimeException("bad request - 잘못된 url 또는 Http Method");
}
물론 RuntimeException은 나중에 다른 팀원이 예외처리를 해주기로 한 컨벤션이다. 나중에 이부분을 400에러로 처리해주는 로직을 작성할 예정이다.(HandlerException사용)
Interceptor에 관해 다른 메서드들도 공부할 수 있는 블로그이다.(나중에 공부할 것)
https://psip31.tistory.com/138
Spring Interceptor 개념 및 동작원리
Spring 관련 첫 게시물!! 사실 실무나 사이드 프로젝트 하면서, Spring은 제일 많이 쓰는 Framework라고 할 수 있다. 하지만 구동원리를 설명하라고 하면 아직도 용어가 입에 안 붙고, 어버버버 할 때가
psip31.tistory.com
https://www.baeldung.com/spring-mvc-handlerinterceptor
https://mangkyu.tistory.com/180
[Spring] 디스패처 서블릿(Dispatcher Servlert)이 HTTP 요청을 처리하는 방법과 핸들러 메소드(HandlerMethod)
이번에는 디스패처 서블릿(Dispatcher Servlert)이 HTTP 요청을 처리하는 방법에 대해서 알아보도록 하자 1. 디스패처 서블릿(Dispatcher Servlert)이 HTTP 요청을 처리하는 방법과 핸들러 메소드(HandlerMethod) [
mangkyu.tistory.com