[Spring] Filter, Interceptor

Donghoon Jeong·2023년 11월 22일
1

Spring

목록 보기
13/15
post-thumbnail

필터 (Filter)

필터 (Filter)는 말 그대로 요청과 응답을 거르는 역할을 합니다.

자세하게 말하자면 필터는 디스패처 서블릿(Dispatcher Servlet)에 요청이 전달되기 전/후에 url 패턴에 맞는 모든 요청에 대해 부가 작업을 처리할 수 있는 기능을 제공합니다. 

디스패처 서블릿은 스프링의 가장 앞단에 존재하는 프론트 컨트롤러이므로, 필터는 스프링 범위 밖에서 처리가 되는 것입니다.

즉, 스프링 컨테이너가 아닌 톰캣과 같은 웹 컨테이너에 의해 관리가 되고, 디스패처 서블릿 전/후에 처리합니다.

스프링 컨테이너에 의해 관리되진 않지만 스프링 Bean으로 등록은 가능합니다.

Filter의 메소드 종류

필터를 사용하기 위해서는 javax.servlet의 Filter 인터페이스를 구현 해야 합니다.


public interface Filter {

    public default void init(FilterConfig filterConfig) throws ServletException {}

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;

    public default void destroy() {}
    
}
  • init()
    필터 객체를 초기화하고 서비스에 추가하기 위한 메소드로, 웹 컨테이너가 init()을 호출하여 필터 객체를 초기화하면 이후 요청들은 doFilter()를 통해 처리됩니다.
  • doFilter()
    url-pattern에 맞는 모든 HTTP 요청이 디스패처 서블릿으로 전달되기 전에 웹 컨테이너에 의해 실행되는 메소드입니다.
    doFilter의 파라미터로 FilterChain이 있는데, FilterChain의
    chain.doFilter()로 전, 후에 우리가 필요한 처리 과정을 넣어줌으로써 원하는 처리를 진행할 수 있고, 이 메소드를 통해 다음 대상으로 요청을 전달할 수도 있습니다.
  • destroy()
    필터 객체를 제거하고 사용하는 자원을 반환하기 위한 메소드로,
    웹 컨테이너가 destroy()를 호출하여 필터 객체를 종료하면 이후에는 doFilter에 의해 처리되지 않습니다.

인터셉터 (Interceptor)

인터셉터 (Interceptor)는 필터와 달리 Spring이 제공하는 기술로써, 디스패처 서블이 컨트롤러를 호출하기 전과 후에 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공합니다.

즉, 웹 컨테이너(서블릿 컨테이너)에서 동작하는 필터와 달리 인터셉터는 스프링 컨테이너에서 동작을 하는 것입니다.

인터셉터는 스프링 컨테이너 내에서 동작하므로 필터를 거쳐 프론트 컨트롤러인 디스패처 서블릿이 요청을 받은 이후에 동작하게 됩니다. 만약 인터셉터가 없다면 바로 컨트롤러가 실행됩니다.

Interceptor의 메소드 종류

인터셉터를 추가하기 위해서는 org.springframework.web.servlet의 HandlerInterceptor 인터페이스를 구현 해야 합니다.

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 메소드
    preHandle 메소드는 컨트롤러가 호출되기 때문에 컨트롤러 이전에 처리해야 하는 전처리 작업이나 요청 정보를 가공하거나 추가하는 경우에 사용할 수 있습니다.
    preHandle의 반환 타입은 boolean인데 반환값이 true이면 다음 단계로 진행이 되지만, false라면 작업을 중단하여 이후의 작업(다음 인터셉터 또는 컨트롤러)은 진행되지 않습니다.
  • postHandle 메소드
    postHandle 메소드는 컨트롤러를 호출된 후에 실행되기 때문에 컨트롤러 이후에 처리해야 하는 후처리 작업이 있을 때 사용할 수 있습니다.
  • afterCompletion 메소드
    모든 뷰에서 최종 결과를 생성하는 일을 포함해 모든 작업이 완료된 후에 실행됩니다. 요청 처리 중에 사용한 리소스를 반환할 때 사용하기에 적합합니다.

세 메소드 모두 default로 구성되어 있기 때문에, 꼭 모든 메소드를 작성 안 하고 필요한 메소드만 오버라이딩해서 작성이 가능합니다.


Filter, Interceptor 비교

예외 처리

앞서 살펴본 그림에서 보이듯이 필터와 인터셉터는 관리되는 영역이 다릅니다. 필터는 스프링 컨테이너 이전의 웹 컨테이너에서 관리되지만, 인터셉터는 스프링 컨테이너 영역에서 관리되는 영역이기 때문에 필터는 스프링의 지원을 받을 수 없습니다.

@RestControllerAdvice
public class GlobalExceptionHandler {
    
    ...
    
}

일반적으로 스프링을 사용한다면 위 코드와 같이 @RestControllerAdvice를 활용하여 예외처리 기능을 주로 사용합니다. 이를 통해 전역적으로 예외 처리 로직을 관리하고 일관된 에러 응답을 생성할 수 있습니다.

하지만 앞서 설명하였듯 필터는 스프링 앞의 서블릿 영역에서 관리되기 때문에 스프링의 지원을 받을 수 없다. 그래서 만약 필터에서 Exception이 발생 했다면, Exception이 처리되지 않고 서블릿까지 전달됩니다.

그에 반면, 인터셉터는 스프링 컨테이너에서 동작하므로 스프링의 예외 처리 기능을 활용할 수 있습니다.

Request/Response 객체 조작 가능 여부

필터는 Request와 Response를 조작할 수 있지만 인터셉터는 조작할 수 없습니다.  
필터의 경우, 다음 필터를 호출하기 위해서는 필터 체이닝(다음 필터 호출)을 해주어야 한다. 그리고 이때 Request/Response 객체를 넘겨주므로 우리가 원하는 Request/Response 객체를 넣어줄 수 있습니다.

public MyFilter implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        // 개발자가 다른 request와 response를 넣어줄 수 있음
        chain.doFilter(new MockHttpServletRequest(), new MockHttpServletResponse());       
    }
    
}

하지만 인터셉터는 처리 과정이 필터와 다릅니다.

디스패처 서블릿이 여러 인터셉터 목록을 가지고 있고, 순차적으로 실행시킵니다.
그리고 true를 반환하면 다음 인터셉터가 실행되거나 컨트롤러로 요청이 전달되며, false가 반환되면 요청이 중단됩니다.

그러므로 다른 request, response 객체를 넘겨줄 수 없습니다.

public class MyInterceptor implements HandlerInterceptor {

    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // Request/Response를 교체할 수 없고 boolean 값만 반환할 수 있다.
        return true;
    }

}

Filter, Interceptor 사용 사례

필터(Filter)의 사용 사례

  • 보안 및 인증/인가 관련 작업
  • 모든 요청에 대한 로깅 또는 검사
  • 이미지/데이터 압축 및 문자열 인코딩

필터는 기본적으로 스프링과 무관하게 전역적으로 처리해야 하는 작업들을 처리할 수 있다.

필터는 인터셉터보다 앞단에서 동작하기 때문에 보안 검사를 하여 올바른 요청이 아닐 경우 차단할 수 있습니다. 그러면 스프링 컨테이너까지 요청이 전달되지 못하고 차단되므로 안전성을 더욱 높일 수 있습니다. Filter를 사용하는 예시로 Spring Security가 있습니다.

또한, 필터는 이미지나 데이터의 압축, 문자열 인코딩과 같이 웹 어플리케이션에 전반적으로 사용되는 기능을 구현하기에 적당합니다.

인터셉터(Interceptor)의 사용 사례

  • 세부적인 보안 및 인증/인가 공통 작업
  • API 호출에 대한 로깅 또는 검사
  • Controller로 넘겨주는 정보의 가공

인터셉터에서는 클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리할 수 있습니다.

예를 들어 특정 그룹의 사용자는 어떤 기능을 사용하지 못하는 경우가 있는데, 이러한 작업들은 컨트롤러로 넘어가기 전에 검사해야 하므로 인터셉터가 처리하기에 적합합니다.

또한, 해당 객체가 내부적으로 갖는 값은 조작할 수 있으므로 컨트롤러로 넘겨주기 위한 정보를 가공하기에 용이합니다.


정리

필터(Filter)는 특정 요청과 컨트롤러에 관계없이 전역적으로 처리해야 하는 작업이나
웹 어플리케이션에 전반적으로 사용되는 기능을 구현할 때 적용하고, 인터셉터(Interceptor)는 클라이언트의 요청과 관련된 작업에 대해 추가적인 요구사항을 만족해야 할 때 적용합니다.

profile
정신 🍒 !

0개의 댓글