[Spring] Filter와 Interceptor - 동작원리와 흐름 이해하기

·2024년 3월 4일
0

Spring

목록 보기
6/6
post-thumbnail

Servlet Filter

클라이언트로 부터 서버로 요청이 들어오는 경우, Dispatcher Servlet 을 거치기전 요청 사항에 대한 공통 관심사를 처리하기 위한 필터 로직을 수행한다. 대표적으로 Spring Security 를 활용하여 요청에 대한 필터 기반 인증, 인가 처리를 수행하기 위해 많이 사용된다.

filter 흐름

  • 올바른 전송 시 : HTTP 요청 -> WAS -> 필터 -> Dispatcher Servlet -> Controller
  • 전송 제한 시 : HTTP 요청 -> WAS -> 필터 -> 유효하지 못한 요청에 대한 응답 반환 (Dispatcher Servlet을 거치지 않고 필터 내에서 바로 반환 )
  • 다중 필터 적용 시 : HTTP 요청 -> WAS -> 필터 1 → 필터 2 → 필터 3 → … -> Dispatcher Servlet -> Controller

filter 주요 메서드

Servlet filterjavax.servlet.Filter 인터페이스를 구현하여 만들어진다. 이를 상속한 구현체는 세 가지 주요 메서드를 사용할 수 있다.

void init(FilterConfig config

필터를 초기화하고 설정하는 메서드로, 일반적으로 스프링 어플리케이션이 실행될 때 한번만 실행된다.

void destroy()

필터가 소멸될 때 호출되는 메서드로, 일반적으로 스프링 어플리케이션이 종료될 때 한번만 실행된다.

void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

실제로 필터가 수행해야하는 로직을 작성하는 메서드이다. 요청이나 응답을 가로채어 적절한 로직을 수행한 후, FilterChain 을 통해 또다른 필터 혹은 Servlet 단으로 전달하는 것이 가능하다.

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    // 요청 처리 로직...

    // 필터 체인을 통해 다음 필터로 또는 서블릿으로 제어를 전달
    chain.doFilter(request, response);

    // 응답 가로채는 로직...
}

Spring 인터셉터

Spring MVC 에서, 웹 어플리케이션 내 특정한 URI 호출을 가로채어 공통 관심사를 처리하기 위한 인터셉터 로직을 수행한다.

Spring Interceptor 주요 메서드

Interceptor 는 개발자가 구현한 로직의 수행을 기준으로, 해당 요청에 대한 전처리와 후처리를 쉽게 구현할 수 있도록 preHandle, postHandle, afterCompletion 등의 세 가지 주요 메서드를 3제공한다.

boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

컨트롤러가 요청 로직을 수행하기 이전 전처리 로직을 수행하는 메서드로, 예를 들어 로그인 여부 및 권한 체크 등을 수행할 수 있다. 반환 값을 boolean 을 반환하며, true 가 반환되는 경우에만 작업을 이어가며, false 의 경우에는 작업을 중단시키게 된다.

작업이 중단되는 경우, 기본적으로 body 가 없는 200 ok 를 반환한다. 물론, response 를 통해 개발자가 설정할 수 있다.

void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler)

컨트롤러가 요청 로직을 수행한 이후 후처리 로직을 수행하는 메서드로, postHandle 의 경우, 앞의 preHandletruereturn 하는 경우에만 수행이 이루어진다.

postHandle 에서 응답 객체 조작하기

결론부터 말하면 RestController를 사용하거나 Controller + ResponseBody 어노테이션을 사용할 때 명확하게 응답을 반환하는 경우 ( ex : dto , String , Entity 등 ) Interceptor 에서 객체에 대한 수정이 불가능하다. Controller 가 로직을 통해 반환한 응답을 수정하는 것 자체가 좋은 접근이 아니라고 판단하는 듯 하다. 이러한 설정들은 filter 역시 동일하게 적용된다.

일반적으로 postHandleView 렌더링 시 추가적인 요소를 설정하기 위해 자주 사용되었다. 현재의 RestAPI 형태의 어플리케이션 서비스에서는 postHandle 로직은 사용이 제한적일 수 밖에 없다.

HttpServletResponseisCommited 메서드를 통해 수정이 가능한지, 아닌지를 판단할 수 있다. (null 이나 void 와 같이, 응답 결과가 없는 것과 유사한 경우에는 수정이 가능하다.)

void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler)

응답 결과를 완전히 보낸 이후 해당 요청을 종료할 때 로직을 수행하는 메서드로, 주로 리소스의 정리나, 로그 기록 등의 작업에 활용된다. afterCompletion 역시, 앞의 preHandle 이나, postHandle 모두 true 를 반환하는 경우에만 afterCompletion 의 호출이 이루어진다.

Spring Interceptor 흐름

  • 올바른 요청 시 : HTTP 요청 -> WAS -> (필터) -> Dispatcher Servlet -> preHandle → Controller → 로직 수행 → postHandle → 응답
  • 전송 제한 (preHandle) : HTTP 요청 -> WAS -> (필터) -> Dispatcher Servlet -> preHandle → 결함 발견 → 응답
  • 다중 Interceptor : HTTP 요청 → WAS → (필터) → Dispatcher Servlet → preHandle 1 → preHandle 2 → … → Controller → 로직 수행 → postHandle 1 → postHandle 2 → … → 응답

filter vs Interceptor

filter 의 경우, 전처리와 후처리를 모두 하나의 메서드에서 수행하며 doFiter , Interceptor 의 경우, 전처리와 후처리를 각각 다른 메서드에서 진행한다. preHandle , postHandle

interceptor 의 경우, Spring 컨테이너 영역 내에서 운영되며, 사용성, 설정, 기본 예외처리가 명확하며, 각 요청에 대한 처리 로직을 수행하기 위해 사용되는 경우가 많고, filter 의 경우에는 Spring 영역에 진입하기 이전 웹 컨테이너 영역으로 분류되어, 다수의 요청에 대한 공통 사항을 적용하는데 사용되는 경우가 많다.

참고
[Spring] 스프링 Interceptor의 동작 과정
[Spring] 스프링 Filter, DoFilter
[Spring Security] Filter 에 대한 오해와 진실 (doFilter의 정확한 작동방식에 대한 심층분석과 Filter의 흐름) (Spring 200 OK but No Content)
spring interceptor
Spring Filter에서 Response 수정하기

profile
새로운 것에 관심이 많고, 프로젝트 설계 및 최적화를 좋아합니다.

0개의 댓글