Spring

[Spring] 필터(Filter) & 인터셉터(Intercepter)

날아 2023. 1. 30. 00:54

1. 필터(Filter)

  • 필터(Filter)는 J2EE 표준 스펙 기능으로 디스패처 서블릿(Dispatcher Servlet)에 요청이 전달되기 전/후에 url 패턴에 맞는 모든 요청에 대해 부가작업을 처리할 수 있는 기능을 제공한다.
  • 디스패처 서블릿은 스프링의 가장 앞단에 존재하는 프론트 컨트롤러이므로, 필터는 스프링 범위밖에서 처리가 된다.
  • 즉, 스프링 컨테이너가 아닌 톰캣과 같은 웹 컨테이너에 의해 관리가 되는 것이고(스프링 빈으로 등록은 된다.), 디스패처 서블릿 전/후에 처리하는 것이다. 

HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러

 

필터 제한 
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러 //로그인 사용자
HTTP 요청 -> WAS -> 필터(적절하지 않은 요청이라 판단, 서블릿 호출X) //비 로그인 사용자
  • 필터에서 적절하지 않은 요청이라고 판단하면 거기에서 끝을 낼 수 있다. 그래서 로그인 여부를 체크하기에 좋다. 

 

필터 체인
HTTP 요청 -> WAS ->  필터1 ->  필터2 ->  필터3 -> 서블릿 -> 컨트롤러
  • 필터는 체인으로 구성되는데, 중간에 필터를 자유롭게 추가할 수 있다. 
  • 예를 들어서 로그를 남기는 필터를 먼저 적용하고, 그 다음에 로그인 여부를 체크하는 필터를 남길 수 있다. 

 

필터 인터페이스 
  • 필터 인터페이스를  구현하고 등록하면 서블릿 컨테이너가 필터를 싱글톤 객체로 생성하고, 관리한다. 
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() : 필터 초기화 메서드, 서블릿 컨테이너가 생성될 때 호출된다.
  • doFilter() : 고객의 요청이 올 때 마다 해당 메서드가 호출된다. 필터의 로직을 구현하면 된다.
  • destroy() : 필터 종료 메서드, 서블릿 컨테이너가 종료될 때 호출된다. 

2. 인터셉터(Intercepter)

  • 스프링이 제공하는 기술로써, 디스패처 서블릿이 컨트롤러를 호출하기 전/후에 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공한다. 
  • 디스패처 서블릿은 핸들러 매핑을 통해 적절한 컨트롤러를 찾도록 요청하는데, 그 결과로 실행 체인(HandlerExecutionChain)을 돌려준다.
  • 이 실행 체인은 1개 이상의 인터셉터가 등록되어 있다면 순차적으로 인터셉터들을 거쳐 컨트롤러가 실행되도록 하고, 인터셉터가 없다면 바로 컨트롤러를 실행한다. 

HTTP 요청 ->WAS-> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러

 

스프링 인터셉터 제한 
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터 -> 컨트롤러 //로그인 사용자
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 스프링 인터셉터(적절하지 않은 요청이라 판단, 컨트롤러 호출 X) // 비 로그인 사용자

 

스프링 인터셉터 체인
HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 인터셉터1 -> 인터셉터2 -> 컨트롤러

 

스프링 인터셉터 인터페이스
public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse
       response,Object handler) throws Exception {}
  
    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 {}
}
  • 서블릿 필터의 경우 단순하게 doFilter() 하나만 제공된다.
  • 인터셉터는 컨트롤 호출 전(preHandle), 호출 후(postHandle), 요청 완료 이후(afterCompletion)와 같이 단계적으로 세분화되어있다.
  • 인터셉터는 어떤 컨트롤러가 호출되었는지 호출 정보를 받을 수 있다. 또한, 어떤 modelAndView가 반환되는지 응답 정보도 받을 수 있다. 

 

preHandle
  • preHandle 메소드는 컨트롤러가 호출되기 전에 실행된다. 그렇기 때문에 컨트롤러 이전에 처리해야 하는 전처리 작업이나 요청 정보를 가공하거나 추가하는 경우에 사용할 수 있다.
  • preHandle의 3번째 파라미터인 handler 파라미터는 핸들러 매핑이 찾아준 컨트롤러 빈에 매핑되는 HandlerMethod라는 새로운 타입의 객체로써, @RequestMapping이 붙은 메소드의 정보를 추상화한 객체이다.
  • 또한 preHandle의 반환 타입은 boolean인데 반환값이 true이면 다음 단계로 진행이 되지만, false라면 작업을 중단하여 이후의 작업(다음 인터셉터 또는 컨트롤러)은 진행되지 않는다. (위 그림 1번에서 끝나버린다.)

 

postHandle
  • postHandle 메소드는 컨트롤러를 호출된 후에 실행된다. 그렇기 때문에 컨트롤러 이후에 처리해야 하는 후처리 작업이 있을 때 사용할 수 있다.
  • 이 메소드에는 컨트롤러가 반환하는 ModelAndView 타입의 정보가 제공되는데, 최근에는 Json 형태로 데이터를 제공하는 RestAPI 기반의 컨트롤러(@RestController)를 만들면서 자주 사용되지는 않는다.
  • 또한 컨트롤러 하위 계층에서 작업을 진행하다가 중간에 예외가 발생하면 postHandle은 호출되지 않는다.

 

afterCompletion
  • afterCompletion 메소드는 이름 그대로 모든 뷰에서 최종 결과를 생성하는 일을 포함해 모든 작업이 완료된 후에 실행된다. 요청 처리 중에 사용한 리소스를 반환할 때 사용하기에 적합하다.
  • postHandler과 달리 컨트롤러 하위 계층에서 작업을 진행하다가 중간에 예외가 발생하더라도 afterCompletion은 반드시 호출된다.
  • 예외와 무관하게 공통 처리를 하려면 afterCompletion()을 사용해야 한다.

 


3. 필터와 인터셉터 차이 및 용도 

필터와 인터셉터 차이 정리 및 요약

 

Request/Response 객체 조작 가능 여부 
  • 필터는 Request와 Response를 조작할 수 있지만 인터셉트는 조작할 수 없다. (내부 상태를 변경한다는 것이 아니라 다른 객체로 바꿔친다는 의미이다.)
public MyFilter implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        // 개발자가 다른 request와 response를 넣어줄 수 있음
        chain.doFilter(request, response);       
    }
    
}
  • 필터가 다음 필터를 호출하기 위해서는 필터 체이닝(다음 필터 호출)을 해주어야 한다. 이때 Request/Response 객체를 넘겨주므로 프로그래머가 원하는 Request/Response 객체를 넣어줄 수 있다. 
  • 하지만 인터셉터는 true나 false에 따라 다음 인터셉트가 실행되거나 컨트롤러로 요청이 전달, 혹은 요청이 중단된다. 그러므로 우리가 다른 Request/Response 객체를 넘겨줄 수 없다. 
public class MyInterceptor implements HandlerInterceptor {

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

}

 

필터의 용도 및 예시 
  • 필터에서는 기본적으로 스프링과 무관하게 역적으로 처리해야하는 작업들을 처리할 수 있다.
  • 대표적으로 보안 공통 작업이 있다.
  • 또한, 필터는 이미지나 데이터의 압축이나 문자열 인코딩과 같이 웹 애플리케이션에 전반적으로 사용되는 기능을 구현하기에 적당하다. 
  • 필터를 인증과 인가에 사용하는 도구로는 SpringSecurity가 있다. SpringSecurity의 특징 중 하나는 Spring MVC에 종속적이지 않다는 것인데, 이러한 이유로는 필터 기반으로 인증/인가 처리를 하기 때문이다. 

 

인터셉터 용도 및 예시
  • 인터셉터에서는 클라이언트 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리할 수 있다. 
  • 대표적으로는 세부적으로 적용해야 하는 인증이나 인가와 같이 클라이언트 요청과 관련된 작업 등이 있다.
  • ex) 특정 그룹의 사용자는 어떤 기능을 사용하지 못할 때, 이러한 작업들은 컨트롤러로 넘어가기 전에 검사해야 하므로 인터셉터가 처리하기에 적합하다. 
  • 인터셉터는 필터와 다르게  Request/Response 객체를 제공받으므로 객체 자체를 조작할 수는 없다. 대신 해당 객체가 내부적으로 갖는 값은 조작할 수 있으므로 컨트롤러로 넘겨주기 위한 정보를 가공하기에 용이하다. 예를 들어 사용자의 ID를 기반으로 조회한 사용자의 정보를 HttpServletRequest에 넣어줄 수 있다. 
  • 또한 API 호출에 대한 정보들을 기록하기에 용이하다. 

 

 

출저

인프런 강의 스프링 MVC 2편 (김영한 강사님)

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard