Spring Boot로 입문하다 보면 스프링으로 만들어진 웹 애플리케이션의 내부적인 동작이나 원리에 대해 궁금한 것이 한두 가지가 아니다. 나 또한 그런 궁금증으로 이 글을 쓰게 되었다. 오늘은 Dispatcher Servlet 전, 후로 동작하는 Filter와 Interceptor에 대해 알아보자.
참고한 블로그 입니다.
디스패처 서블릿은 가장 앞단에서 HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해 주는 프런트 컨트롤러(Front Controller)라고 정의할 수 있다.
이것을 보다 자세히 설명하자면, 클라이언트로부터 어떠한 요청이 오면 Tomcat과 같은 서블릿 컨테이너가 요청을 받게 된다. 그리고 이 모든 요청을 먼저 프런트 컨트롤러인 디스패처 서블릿이 받게 된다. 그러면 디스패처 서블릿은 공통적인 작업을 먼저 처리한 후에 해당 요청을 처리해야 하는 세부 컨트롤러를 getBean()으로 가져오고, 정해진 메서드를 실행시켜 작업을 위임한다.
예를 들어 예외가 발생하였을 때 일관된 방식으로 처리하는 것도 프런트 컨트롤러인 디스패처 서블릿이 담당하고 있습니다.
먼저 Filter와 Interceptor에 대해 공부하다 보면 다음과 같은 라이프 사이클을 많이 보았을 것이다.
이처럼 Filter와 Interceptor는 Dispatcher-Servlet 전, 후로 동작하는 것을 확인할 수 있다. 그럼 각각의 특징에 대해 더 자세히 알아보자.
필터는 J2EE 표준 스펙 기능으로 디스패처 서블릿에 요청이 전달되기 전, 후에 url 패턴에 맞는 모든 요청에 대해 부가 작업을 처리할 수 있는 기능을 제공한다. 즉, 스프링 컨테이너가 아닌 톰캣과 같은 웹 컨테이너에 의해 관리가 되므로 디스패처 서블릿으로 가기 전에 요청을 처리하는 것이다.
그렇기 때문에 필터에서는 스프링과 무관하게 전역적으로 처리해야 하는 작업들을 수행하면 좋다.
대표적인 예시로 보안과 관련된 공통 작업이 있다. 필터는 인터셉터보다 앞단에서 동작하기 때문에 전역적으로 해야 하는 보안 검사(XSS 방어 등)를 하여 올바른 요청이 아닐 경우 차단을 할 수 있다. 그러면 스프링 컨테이너까지 요청이 전달되지 못하고 차단되므로 안정성을 더욱 높일 수 있다.
또한 필터는 이미지나 데이터의 압축이나 문자열 인코딩과 같이 웹 애플리케이션에 전반적으로 사용되는 기능을 구현하기에 적당하다. Filter는 다음 체인으로 넘기는 ServletRequest/ServletResponse 객체를 조작할 수 있다는 점에서 Interceptor보다 훨씬 강력한 기술이다.
인터셉터에서는 클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리할 수 있다.
대표적으로 인증이나 인가와 같이 클라이언트 요청과 관련된 작업 등이 있다. 이러한 작업들은 컨트롤러로 넘어가기 전에 검사해야 하므로 인터셉터가 처리하기에 적합하다.
또한 인터셉터는 필터와 다르게 HttpServletRequest나 HttpServletResponse 등과 같은 객체를 제공받으므로 객체 자체를 조작할 수는 없다. 대신 해당 객체가 내부적으로 갖는 값은 조작할 수 있으므로 컨트롤러로 넘겨주기 위한 정보를 가공하기에 용이하다. 예를 들어 JWT 토큰 정보를 파싱 해서 컨트롤러에게 사용자의 정보를 제공하도록 가공할 수 있는 것이다.
그 외에도 우리는 다양한 목적으로 API 호출에 대한 정보들을 기록해야 할 수 있다. 이러한 경우에 HttpServletRequest나 HttpServletResponse를 제공해 주는 인터셉터는 클라이언트의 IP나 요청 정보들을 포함해 기록하기에 용이하다.
정리
필터와 인터셉터 모두 비즈니스 로직과 분리되어 특정 요구사항(보안, 인증, 인코딩)을 만족시켜야 할 때 적용하면 좋다. 하지만 필터는 보통 특정 요청과 컨트롤러에 관계없이 전역적으로 적용하면 좋을 때 사용하면 좋다는 것이고, 인터셉터는 요청과 관련된 작업에 대한 추가적인 요구사항을 만족해야 할 때 적용하면 좋다는 것이다. 모든 API가 인증을 요구하진 않을 수도 있으니까 말이다. 그럴 땐 인터셉터를 이용해 특정 요청에 대해서만 인증을 요구하도록 하면 될 것이다.