Spring (Boot)

Filter 와 Interceptor의 차이점

superbono 2021. 12. 7. 16:35

필터와 인터셉터 둘 다 막연하게 늬앙스 자체가 뭔가... 들어오는 요청을 한 번 걸러주는 역할을 한다고 두루뭉실하게 생각했었다.

그래서 한번 정확하게 역할을 정의하고 분석할 필요가 있다고 생각되어 따로 포스팅을 하게 되었다.

 

* 필요한 사전 지식

스프링은 디스패처 서블릿이 핸들러 매핑을 통해 해당 요청을 처리할 적절한 컨트롤러를 찾는다.

 

필터는 dispatcherServlet의 앞에, interceptor는 dispatcherServlet과 Controller의 사이에 위치하게 된다.  출처 : https://www.baeldung.com/spring-mvc-handlerinterceptor-vs-filter

 

 

Filter

- web application에 등록이 된다. 

필터는 스프링 프레임워크의 일부가 아닌 웹 서버(ex. 톰캣)의 일부이다. 따라서 DispatcherServlet 앞단에 위치하며 정보를 처리해준다. 필터를 사용해서 서블릿에 정보가 도달하지 못하도록 막을 수도 있고, 서블릿을 통과한 클라이언트에게 가는 응답을 차단할 수도 있다. filter에서 예외가 발생하면 web application 레벨에서 처리를 해야한다. 

 

필터 생성

javax.servlet.Filter 인터페이스를 구현하는 클래스를 생성한다. 

@Component
public class LogFilter implements Filter {

    private Logger logger = LoggerFactory.getLogger(LogFilter.class);
    
    @Override
     public void init(FilterConfig config) throws ServletException {

	}

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
      throws IOException, ServletException {
        logger.info("Hello" + request.getLocalAddr());
        chain.doFilter(request, response);
    }
    
    @Override
    public void destory(){
    
    }
}

init() : 필터 객체가 생성 및 초기화 될 때 한 번 실행된다. FilterConfig 객체를 통해 web.xml에서 설정해둔 설정 값을 가져올 수 있다. 이후 요청들은 doFilter를 통해 처리된다. 

doFilter() : FilterChain의 doFilter를 통해 다음 대상으로 요청을 전달하게 된다.  

destory() : 필터 인스턴스 종료 시 실행됨

+)

@Component 로 어노테이션 추가해서 스프링 컨텍스트에 필터 추가해주기

 

Interceptor

- spring framework에서 자체적으로 제공하는 기능. spring container에 등록된다. 

- dispatcherServlet에서 핸들러 매핑 후 controller로 가기 전/후에 active

 

인터셉터 생성

org.springframework.web.servlet.HandlerInterceptor 인터페이스를 구현하는 클래스를 생성한다. 

public class MyInterceptor implements HandlerInterceptor {

    private Logger logger = LoggerFactory.getLogger(LogInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) 
      throws Exception {
        logger.info("===== preHandle =====");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 
      throws Exception {
        logger.info("===== postHandle =====");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) 
      throws Exception {
        logger.info("===== afterCompletion =====");
    }

}

 preHandle(): 대상 핸들러(컨트롤러)가 호출되기 전에 실행된다. 따라서 컨트롤러 이전에 처리해야 하는 전처리 작업이나 요청 정보를 파싱, 추가하는 경우에 유용하다. 

postHandle(): 대상 핸들러(컨트롤러) 이후에 실행되지만 DispatcherServlet이 뷰를 렌더링 하기 전에 실행된다. 

afterCompletion(): 요청 처리 및 뷰 렌더링 완료 후 콜백

메소드들 덕분에 servlet 안에서도 메서드에 따라 실행 시점을 다르게 지정할 수 있다. 

 

Filter vs Interceptor

  필터 인터셉터
소속 웹 컨테이너 스프링 컨테이너
request/response 조작 가능 여부 O X
용도  1. 모든 요청에 대한 로깅 및 감사
2. 이미지 및 데이터 압축
3. 보안 관련 공통 작업
1. api 호출에 대한 로깅 및 감사
2. spring context 또는 모델(뷰) 조작
3. controller로 넘기기 전, 전처리 작업
4. 인증/인가와 같은 공통의 작업

따라서 filter는 dispatcherservlet 앞단에 위치하는 만큼, 스프링과 무관한 전역적으로 처리가 필요한 작업들을 처리하는데 활용된다. 좀 더 러프한...? 덩어리가 큰? 작업을 처리한다. 

interceptor는 클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리한다. 

 

 

Filter에서 request/response 를 조작할 수 있다? 

public class MyFilter implements Filter {
 
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    HttpServletRequest requestWrapper = Manager.getRequestWrapper(request);
    
    chain.doFilter(requestWrapper, response);
    
  }
}

서버 유지 보수를 위해서 requestBody를 로깅한다고 생각해보자. 로깅을 하려면 일단 body를 읽어야한다.

그런데 문제는 Request Body 는 한번만 읽을 수 있다. 이유는 HttpServletRequest의 InputStream 은 한번 읽으면 다시 못읽기 때문에. 다시 읽으려고 하면 Exception 파티 일어난다. 

따라서 HttpServletRequest를 여러번 감싸서 inputStream을 여러번 열 수 있도록 ServletRequest를 커스터마이징해준다. 

 

요약 

filter와 interceptor의 차이점

1. filter는 web application에 등록 -> dispatcherServlet 앞단에 위치 / interceptor는 spring container에 등록 -> dispatcherServlet과 controller 사이에 위치2. 따라서 filter 에서 exception이 발생하면 좀 더 상위의 레벨에서 대응해야 함 그런데 interceptor에서 exception이 발생하면 그냥 @exceptionhandler 사용하면 됨 interceptor는 spring context 안에 있으니까!

 

 

참고 

https://mangkyu.tistory.com/173

 

[Spring] 필터(Filter) vs 인터셉터(Interceptor) 차이 및 용도

Spring은 공통적으로 여러 작업을 처리함으로써 중복된 코드를 제거할 수 있도록 많은 기능들을 지원하고 있다. 이번에는 그 중에서 필터(Filter) vs 인터셉터(Interceptor)의 차이에 대해 알아보고자

mangkyu.tistory.com

https://www.baeldung.com/spring-mvc-handlerinterceptor-vs-filter

 

'Spring (Boot)' 카테고리의 다른 글

@PostConstruct 의 사용 이유  (0) 2021.12.26