
웹 요청 흐름 속에서 필터와 인터셉터의 역할
Spring Application에서 사용자의 요청은 단순히 컨트롤러에 바로 도달하지 않는다.
요청은 여러 계층을 거쳐 처리되며, 이 과정에서 Filter와 Interceptor는 각각의 위치에서 중요한 역할을 수행한다.
결국, Filter & Interceptor는 웹 요청 흐름에서 공통 관심사(Cross-Cutting Concern)를 깔끔하게 분리할 수 있도록 도와주며, 유지보수성과 확장성을 크게 높여준다.
왜 알아야 할까?
실무에서는 사용자 인증/인가, 요청 로깅, 성능 측정, 응답 조작 등 다양한 전/후처리 작업이 요구된다.이때 Filter와 Interceptor를 적절히 선택하고 구현할 수 있어야, 깔끔하고 안정적인 API 서비스를 제공할 수 있다.
또한, 이 둘은 AOP, ArgumentResolver 등과 함께 Spring 생태계에서 핵심적인 미들웨어 구성 요소로, 그 동작 위치와 원리를 이해하는 것은 필수적이다.
Servlet Filter 개념
Filter는 JavaEE(or Jakarta EE)의 표준 Servlet 스펙의 일부로, 클라이언트 요청이 서블릿(혹은 Spring의 DispatcherServlet)에 도달하기 이전 또는 이후에 요청/응답 객체를 가로채 처리할 수 있는 컴포넌트이다.
실행 시점 예시
요청 인코딩 처리, 응답 압축(Gzip), XSS 방지, JWT 토큰 추출 등
실행 시점: DispatcherServlet 이전
Filter는 DispatcherServlet보다 앞서 동작하기 때문에, Spring Context에 접근하지 않아도 모든 요청을 가로챌 수 있다. 따라서 Spring의 Controller, Service 로직과는 별개로 전역적인 요청 흐름 제어에 적합하다
전/후 처리 방식
Filter는 아래 구조처럼 동작하며, 체인 방식으로 필터링 로직을 구성할 수 있다.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 요청 전 처리
chain.doFilter(request, response); // 다음 필터 or 서블릿으로 전달
// 응답 후 처리
}
코드 예제: OncePerRequestFilter 기반 로깅 필터
@Component
public class LoggingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
log.info("Request: [{}] {}", request.getMethod(), request.getRequestURI());
filterChain.doFilter(request, response); // 다음 필터 or 서블릿으로 전달
long duration = System.currentTimeMillis() - startTime;
log.info("Response: [{}] {} ({}ms)",
response.getStatus(), request.getRequestURI(), duration);
}
}
위 필터는 모든 요청과 응답을 로깅하며, 처리 시간을 측정하는 데도 활용 가능하다.
Spring HandlerInterceptor 개념
Interceptor는 Spring MVC에서 제공하는 기능으로, 컨트롤러 핸들러(ex. @RequestMapping)가 실행되기 전/후에 공통 로직을 삽입할 수 있도록 도와주는 컴포넌트다.
org.springframework.web.servlet.HandlerInterceptor 인터페이스 구현실행 시점: DispatcherServlet 이후, Controller 전/후
Filter와 달리 Interceptor는 Spring의 DispatcherServlet 이후에 동작하며, HandlerMapping에 의해 선택된 선트롤러가 실행되기 전/후의 시점을 제어할 수 있다.
즉, Spring MVC 컨트롤러와 밀접하게 연결되어 있으며, 요청 흐름 안에서 더욱 세밀한 제어가 가능하다.
코드 예제: 로그인 인증 인터셉터
@Component
public class AuthInterceptor implements HandlerInterceptor {
private final JwtTokenProvider jwtTokenProvider;
public AuthInterceptor(JwtTokenProvider jwtTokenProvider) {
this.jwtTokenProvider = jwtTokenProvider;
}
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws IOException {
String authHeader = request.getHeader("Authorization");
// Authorization 헤더 없거나 형식이 잘못된 경우
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Unauthorized: No or Invalid Authorization header");
return false;
}
String token = authHeader.substring(7); // "Bearer " 제거
// 토큰 유효성 검증 실패
if (!jwtTokenProvider.validateToken(token)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Unauthorized: Invalid token");
return false;
}
// 토큰에서 사용자 정보 추출 후 context에 저장 (선택 사항)
String userId = jwtTokenProvider.getUserIdFromToken(token);
request.setAttribute("userId", userId);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler,
Exception ex) {
// 요청 완료 후 리소스 정리, 로깅 등
log.info("✅ Completed request: {}", request.getRequestURI());
}
}
| 메서드 | 실행 시점 | 주요 역할 |
|---|---|---|
preHandle() | 컨트롤러 실행 이전 | 인증 검사, 요청 거절 가능 (false 반환 시 중단) |
postHandle() | 컨트롤러 실행 이후, View 렌더링 이전 | 모델 데이터 가공, 추가 정보 삽입 등 |
afterCompletion() | View 렌더링 이후 | 예외 처리, 리소스 정리, 로깅 등 |
| 항목 | Filter | Interceptor |
|---|---|---|
| 실행 위치 | DispatcherServlet 이전, 가장 바깥단에서 동작 | DispatcherServlet 이후, 컨트롤러 호출 전/후에 동작 |
| 기반 기술 | Java EE Servlet 표준 (javax.servlet.Filter) | Spring MVC (HandlerInterceptor) |
| 주요 목적 | 요청/응답 전처리, 인코딩, CORS, 보안 필터링 | 인증, 인가, 컨트롤러 후처리, 로깅 등 |
| 적용 대상 | 모든 요청 (HttpServletRequest, HttpServletResponse) | 컨트롤러 핸들러 (@Controller, @RequestMapping 등) |
| 등록 방식 | @Component, FilterRegistrationBean 사용 | WebMvcConfigurer.addInterceptors() 오버라이딩 |
| 동작 메서드 | doFilter() 메서드 하나만 사용 | preHandle(), postHandle(), afterCompletion() 세 가지 메서드 제공 |
| 예외 처리 | 예외 발생 시 체인 다음 필터로 전달 안됨 | afterCompletion()에서 예외 후처리 가능 |
| 빈 주입 | Servlet 스펙상 Spring 빈 주입이 제한적임 | Spring 컨텍스트 기반이므로 DI 완전 지원 |
| 사용 예시 | XSS 방지, 로깅, 응답 압축, 토큰 파싱 등 | 사용자 인증, 권한 체크, 요청/응답 로깅, 세션 검증 등 |
전역 전처리 로직 (모든 요청에 공통 적용되는 작업): Filter 사용 권장
예: CORS 설정, XSS 방지, 공통 인코딩 처리 등
컨트롤러 전후 흐름 제어가 필요한 경우: Interceptor 사용
예: 사용자 인증/인가, 세션 체크, 응답 데이터 후처리 등
출처
https://www.baeldung.com/spring-boot-add-filter
https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-config/interceptors.html