이 글은 Velog에서 이전한 글입니다. Velog 원문 보기
서론
웹 요청 흐름 속에서 필터와 인터셉터의 역할
Spring Application에서 사용자의 요청은 단순히 컨트롤러에 바로 도달하지 않는다.
요청은 여러 계층을 거쳐 처리되며, 이 과정에서 Filter와 Interceptor는 각각의 위치에서 중요한 역할을 수행한다.
- Filter: Servlet Container 수준에서 요청과 응답을 감싸며, 보안, 로깅, 인코딩 처리 등의 전역적인 전처리에 사용된다.
- Interceptor: Spring MVC의 DispatcherServlet 이후에 동작하며, 컨트롤러 실행 전후에 추가 로직을 삽입할 수 있다.
결국, Filter & Interceptor는 웹 요청 흐름에서 공통 관심사(Cross-Cutting Concern)를 깔끔하게 분리할 수 있도록 도와주며, 유지보수성과 확장성을 크게 높여준다.
왜 알아야 할까?
실무에서는 사용자 인증/인가, 요청 로깅, 성능 측정, 응답 조작 등 다양한 전/후처리 작업이 요구된다.이때 Filter와 Interceptor를 적절히 선택하고 구현할 수 있어야, 깔끔하고 안정적인 API 서비스를 제공할 수 있다.
또한, 이 둘은 AOP, ArgumentResolver 등과 함께 Spring 생태계에서 핵심적인 미들웨어 구성 요소로, 그 동작 위치와 원리를 이해하는 것은 필수적이다.
Filter란 무엇인가?
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 기반 로깅 필터
- Spring Boot에서는 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);
}
}
위 필터는 모든 요청과 응답을 로깅하며, 처리 시간을 측정하는 데도 활용 가능하다.
Interceptor란 무엇인가?
Spring HandlerInterceptor 개념
Interceptor는 Spring MVC에서 제공하는 기능으로, 컨트롤러 핸들러(ex. @RequestMapping)가 실행되기 전/후에 공통 로직을 삽입할 수 있도록 도와주는 컴포넌트다.
org.springframework.web.servlet.HandlerInterceptor인터페이스 구현- 주로 인증, 권한 검사, 요청/응답 로깅, 사용자 세션 검사 등에 활용됨
- Spring Context 안에서 동작하므로, 의존성 주입이 자유롭고, Spring 빈 사용도 가능
실행 시점: 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, postHandle, afterCompletion 동작 원리
| 메서드 | 실행 시점 | 주요 역할 |
|---|---|---|
preHandle() |
컨트롤러 실행 이전 | 인증 검사, 요청 거절 가능 (false 반환 시 중단) |
postHandle() |
컨트롤러 실행 이후, View 렌더링 이전 | 모델 데이터 가공, 추가 정보 삽입 등 |
afterCompletion() |
View 렌더링 이후 | 예외 처리, 리소스 정리, 로깅 등 |
Filter VS Interceptor
| 항목 | 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사용
예: 사용자 인증/인가, 세션 체크, 응답 데이터 후처리 등
결론
핵심 요약
- Filter는 Servlet 기반, 전역 요청 흐름 제어에 적합
- Interceptor는 Spring MVC 기반, 컨트롤러 전후 세밀한 로직 제어에 적합
- 실무에서는 목적과 위치에 따라 적절한 도구 선택이 중요함
확장 개념 추천 학습
- AOP (Aspect-Oriented Programming): 더 세밀하고 유연한 전후처리
- HandlerMethodArgumentResolver: 컨트롤러 파라미터 가공
- ExceptionHandler / ControllerAdvice: 글로벌 에러 핸들링
출처
https://www.baeldung.com/spring-boot-add-filter
https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-config/interceptors.html
'Backend > Spring' 카테고리의 다른 글
| Spring Boot 4에서 사라진 ObjectMapper Bean (0) | 2026.08.05 |
|---|---|
| [Spring] Spring Batch: 대용량 배치 처리의 핵심 프레임워크 (0) | 2026.08.02 |
| ✏️ [Spring] Bean 생명주기 (0) | 2026.08.01 |
| [Spring] 역할과 구현의 분리, 스프링 컨테이너의 필요성 (0) | 2026.07.31 |
| ✏️ [Spring] Spring Security Testing (0) | 2026.07.31 |