본문 바로가기

TIL(Today I Learned)

TIL-231019(Filter와 Interceptor)

📝오늘 공부한 것

  • Filter와 Interceptor 공부
  • 커리어톤 참여하기
  • 프로그래머스 문제풀기
  • 이력서 수정하기

📌Filter와 Interceptor

웹 개발을 하다보면, 공통적으로 처리해야 할 업무들이 많다.

예를 들어, 로그인 관련 처리, 권한 체크, XSS(Cross site script)방어, 분기처리, 로그, 페이지 인코딩 변환 등이 있다.

공통업무에 관련된 코드를 모든 페이지 마다 작성 해야한다면 중복된 코드가 많아지게 되고 프로젝트 단위가 커질수록 서버에 부하를 줄 수도 있으며, 소스 관리도 되지 않는다.

이렇게 많은 로직에서 공통으로 관심이 있는 부분을 공통 관심사라고 한다.
웹과 관련된 공통 관심사를 처리할 때는 HTTP의 헤더나 URL 정보가 필요한데 서블릿 필터나, 스프링 인터셉터는 HttpServletRequest를 제공하기 때문에 AOP 보다는 Filter나 Interceptor에서 처리하는게 좋다.

 

[ Filter ]

  • 필터는 Dispatcher Servlet에 요청이 전달되기 전/후에 url 패턴에 맞는 모든 요청에 대해 부가작업을 처리할 수 있는 기능을 제공한다.
  • 스프링 컨테이너가 아닌 톰캣과 같은 웹 컨테이너(서블릿 컨테이너)에 의해 관리가 된다.(스프링 빈으로 등록이 된다). 

https://mangkyu.tistory.com/173

필터 흐름

HTTP요청 -> WAS -> Filter -> Dispatcher Servlet -> Controller

 

필터 구현

필터를 추가하기 위해서는 javax.servlet의 Filter 인터페이스를 구현해야 하며 3가지 메서드를 가지고 있다.

1. init( ) - 필터 인스턴스 초기화

  • 필터 객체를 초기화하고 서비스에 추가하기 위한 메서드
  • 웹 컨테이너가 1회 init 메서드를 호출하여 필터 객체를 초기화하면 이후의 요청들은 doFilter를 통해 처리된다.

 

2. doFilter( ) - 전/후 처리

  • url-pattern에 맞는 모든 HTTP 요청이 디스패처 서블릿으로 전달되기 전에 웹 컨테이너에 의해 실행되는 메서드
  • doFilter의 파라미터로는 FilterChain이 있는데, FilterChain의 doFilter를 통해 다음 대상으로 요청을 전달하게 된다.
  • chain.doFilter( ) 전/후에 필요한 처리 과정을 넣어줌으로써 원하는 처리를 진행할 수 있다.
  • chain.doFilter(request, response)를 넣으면 필터를 체인으로 수행할 수 있다. 호출할 추가 필터가 없으면 Servlet이 뜬다. 반드시 넣어야 하고, 넣지 않으면 다음 단계로 진행되지 않는다.

 

3. destroy( ) - 필터 인스턴스 종료

  • 필터 객체를 서비스에서 제거하고 사용하는 자원을 반환하기 위한 메서드
  • 웹 컨테이너에 의해 1번 호출되며 이후에는 doFilter에 의해 처리되지 않는다.

✅ init, destroy 메서드는 default 메서드이기때문에 따로 구현하지 않아도 된다.

 

용도 및 예시

  • 공통된 보안 및 인증/인가 관련 작업
  • 모든 요청에 대한 로깅 또는 감사
  • 이미지/데이터 압축 및 문자열 인코딩
  • Spring과 분리되어야 하는 기능

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

대표적으로 보안 공통 작업이 있다. 필터는 인터셉터보다 앞단에서 동작하므로 전역적으로 해야하는 보안 검사를 하여 올바른 요청이 아닐 경우 차단할 수 있다. 그렇게 되면 스프링 컨테이너까지 요청이 전달되지 못하고 차단되므로 안정성을 높일 수 있다.

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

 

[ Interceptor ]

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

https://lovemesomecoding.com/spring-study-guide/spring-study-guide-web-layer

Interceptor 흐름

HTTP요청 -> WAS -> Filter -> Dispatcher Servlet -> Interceptor -> Controller

 

Interceptor 구현

인터셉터를 추가하기 위해서는 web.servlet의 HandlerInterceptor 인터페이스를 구현해야 하며, 3가지 메서드를 가지고 있다.

1. preHandle( ) - Controller메서드가 실행되기 전

  • 컨트롤러가 호출되기 전에 실행
  • 컨트롤러 이전에 처리해야 하는 전처리 작업이나 요청 정보를 가공하거나 추가하는 경우에 사용할 수 있다.
  • 반환타입은 boolean으로 반환값이 true면 다음 단계로 진행이 되지만, false라면 작업을 중단하여 이후의 작업은 진행되지 않는다.

2. postHandle( ) - Controller메서드 실행 직후 view 페이지 렌더링 되기 전

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

3. afterCompletion( ) - view페이지가 렌더링 되고 난 후

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

 

용도 및 예시

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

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

 

[ Filter와 Interceptor의 차이 ]

https://mangkyu.tistory.com/173

 

1. 관리되는 컨테이너

필터는 스프링 이전의 서블릿 영역에서 관리되지만, 인터셉터는 스프링 영역에서 관리되는 영역이기 때문에 필터는 스프링이 처리해주는 내용들을 적용 받을 수 없다. 이로 인한 차이로 발생하는 대표적인 예시가 스프링에 의한 예외처리가 되지 않는다는 것이다.

현재는 필터가 스프링 빈으로 등록이 가능하며, 다른 곳에 주입되거나 다른 빈을 주입받을 수 도 있다.

 

2. 스프링의 예외처리 여부

일반적으로 스프링을 사용한다면 @ControllerAdvice와 @ExceptionHandler를 이용한 예외처리 기능을 주로 사용한다. 그러나 필터는 스프링 앞의 서블릿 영역에서 관리되기 때문에 스프링의 지원을 받을 수 없다. 따라서, 필터에서 예외가 발생하면 에러가 처리되지 않고 서블릿까지 전달된다. 이를 해결하려면 필터에서 응답 객체에 예외 처리를 해주어야한다.

 

3. Request/Response 객체 조작 가능 여부

필터는 Request와 Response를 조작할 수 있지만 인터셉터는 조작할 수 없다. 여기서 조작한다는 것은 내부 상태를 변경한다는 것이 아니라 다른 객체로 바꿔친다는 의미이다.

필터가 다음 필터를 호출할 때 Request/Response 객체를 넘겨주므로 원하는 Request/Response 객체를 넣어줄 수 있다.

그러나, 인터셉터는 디스패처 서블릿이 여러 인터셉터 목록을 가지고 있고, for문으로 순차적으로 실행시킨다. true를 반환하면 다음 인터셉터가 실행되거나 컨트롤러로 요청이 전달되며, false가 반환되면 요청이 중단된다.
-> Request/Response를 교체할 수 없고 boolean값만 반환할 수 있다.

 

[ Filter, Interceptor, AOP ]

https://goddaehee.tistory.com/154

  • Interceptor와 Filter는 Servlet 단위에서 실행된다.
  • 반면 AOP는 메서드 앞에 proxy패턴의 형태로 실행된다.

AOP

  • OOP를 보완하기 위해 나온 개념으로 주로 로깅, 트랜잭션, 에러 처리 등 비즈니스단의 메서드에서 조금 더 세밀하게 조정하고 싶을 때 사용한다.
  • Interceptor나 Filter와는 달리 메서드 전후의 지점에서 자유롭게 설정이 가능하다.
  • Interceptor나 Filter는 주소로 대상을 구분해서 걸러내야하는 반면, AOP는 주소, 파라미터, 애노테이션 등 다양한 방법으로 대상을 지정할 수 있다.

AOP의 포인트컷

@Before: 대상 메서드의 수행 전

@After: 대상 메서드의 수행 후

@After-returning: 대상 메서드의 정상적인 수행 후

@After-throwing: 예외발생 후

@Around: 대상 메서드의 수행 전/후

 

 

Filter와 Interceptor 모두 요청에 대해 일관된 작업을 할 때 코드의 중복을 줄이고 유지보수성을 높인다.
둘의 차이점으로는 적용되는 순서와 범위, 예외처리 여부 등이 있다.

 

느낀 점🤔

 프로젝트를 진행하면서 filter에서 유효하지 않은 토큰이 들어왔을 때에 대한 예외처리를 @ExceptionHandler를 통해 처리했었다. 그런데 Postman으로 확인했을때 예외메시지가 나오지 않는 것이었다. 그때는 'filter부분이라 Handler로 다룰 수 없어 예외처리를 다른 방법으로 해줘야 한다.'는 정도만 이해하고 넘어갔었다.

 이번 Filter와 Interceptor공부를 통해서 어떠한 이유때문에 내가 만들었었던 ExceptionHandler로 예외처리를 할 수 없는지를 이해할 수 있었다.

 다음 프로젝트를 할 때는 상황에 맞게 Filter와 Interceptor 중에 어떠한 것을 사용해야할지 고민을 하면서 코드를 작성해야겠다.

 

 

 

References :

https://mangkyu.tistory.com/173

https://goddaehee.tistory.com/154

https://catsbi.oopy.io/9ed2ec2b-b8f3-43f7-99fa-32f69f059171