2024. 10. 9. 12:50ㆍSpring Framework/Web on Servlet Stack
HTTP Request의 속성(attribute)은 서블릿 필터(Servlet Filter)나 핸들러 인터셉터(HandlerInterceptor) 등의 컴포넌트가 처리하는 동안 추가하는 추가적인 데이터입니다. 이 속성은 request scope 내에서 사용되며, 요청이 시작되어 끝날 때까지 유지됩니다. 요청 속성은 일반적인 요청 헤더나 본문과는 달리, 서버 쪽에서 생성 및 관리되며, 주로 서버 내에서 특정 요청에 대한 데이터를 다른 컴포넌트에 전달하기 위한 목적을 가집니다.
HTTP 요청 속성의 역할
- 추가 데이터 전달: 필터나 인터셉터에서 요청을 처리할 때, 특정한 정보를 다른 컨트롤러로 전달해야 할 경우 요청 속성을 사용합니다. 예를 들어, 인증 정보를 필터에서 처리한 후, 이 정보를 컨트롤러로 전달할 때 요청 속성으로 저장할 수 있습니다.
- 요청의 상태 관리: 필터 또는 인터셉터가 요청의 상태를 기록하거나 처리한 데이터를 저장하고, 이후 컨트롤러 또는 뷰에서 그 데이터를 사용할 수 있도록 합니다.
요청 속성과 관련된 컴포넌트
- Servlet Filter (서블릿 필터): HTTP request가 컨트롤러에 도달하기 전에 처리되는 컴포넌트입니다. 필터에서
request.setAttribute()
메서드를 사용하여 요청 속성을 추가할 수 있습니다. - HandlerInterceptor (핸들러 인터셉터): 스프링 프레임워크에서 요청이 컨트롤러로 들어가기 전이나 후에 추가적인 처리를 할 수 있는 컴포넌트입니다. 인터셉터에서도 필터와 유사하게 요청 속성을 추가하거나 수정할 수 있습니다.
예시: 요청 속성 설정과 사용
- 서블릿 필터에서 요청 속성 설정하기
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
public class ClientFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
Client client = new Client(1, "John Doe"); // 가상의 Client 객체 생성
httpRequest.setAttribute("client", client); // 요청 속성에 Client 객체 저장
chain.doFilter(request, response); // 필터 체인 실행
}
@Override
public void destroy() {}
}
- 컨트롤러에서 요청 속성 사용하기
import org.springframework.web.bind.annotation.RequestAttribute;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.stereotype.Controller;
@Controller
public class ClientController {
@GetMapping("/client")
public String handle(@RequestAttribute("client") Client client) {
System.out.println("Client ID: " + client.getId());
return "clientDetails";
}
}
요청 속성의 특징
- 요청 범위에서만 유효: 요청 속성은 HTTP 요청이 시작되고 끝날 때까지만 유효합니다. 요청이 완료되면 해당 속성은 더 이상 유효하지 않습니다.
- 서버 측에서 설정: 요청 속성은 서버 측에서 설정되는 값으로, 클라이언트는 이를 직접 전송하지 않습니다. 주로 서버 내에서 데이터를 처리하는 과정에서 다른 컴포넌트와 데이터를 공유하기 위해 사용됩니다.
- 클라이언트에게 노출되지 않음: 요청 속성은 HTTP 헤더나 본문과 달리 클라이언트와는 직접적인 관련이 없으며, 클라이언트는 이 속성의 존재를 알지 못합니다.
요청 속성과 세션 속성의 차이
- 요청 속성은 한 번의 요청이 끝나면 소멸하는 데이터입니다. 즉, 요청이 끝날 때까지 데이터를 유지하고 이후에 제거됩니다.
- 세션 속성은 HTTP 세션을 통해 여러 요청에 걸쳐 데이터를 유지합니다. 세션 속성은 클라이언트와의 상호작용을 여러 요청에 걸쳐 지속적으로 처리할 때 유용합니다.
WebFlux에서의 요청 속성 처리
Spring WebFlux에서는 @RequestAttribute
대신 ServerWebExchange
를 통해 요청 속성에 접근합니다. WebFlux는 비동기적으로 작동하므로 요청 속성도 비동기적으로 처리합니다.
WebFlux 예시
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@RestController
public class ReactiveClientController {
@GetMapping("/client")
public Mono<String> handle(ServerWebExchange exchange) {
Client client = exchange.getAttribute("client"); // 요청 속성에서 client 가져오기
if (client != null) {
return Mono.just("Client ID: " + client.getId());
} else {
return Mono.just("No client in request.");
}
}
}
요약
- 요청 속성은 필터나 인터셉터에서 설정된 값을 컨트롤러에서 사용하기 위해 HTTP 요청 범위 내에서 유지되는 데이터입니다.
@RequestAttribute
를 사용하여 이러한 요청 속성에 접근할 수 있으며, 요청이 끝나면 속성도 소멸됩니다.- Spring WebFlux에서는
ServerWebExchange
를 통해 비동기적으로 요청 속성에 접근할 수 있습니다.
ClientFilter
와 같은 서블릿 필터(Servlet Filter)를 스프링 애플리케이션에 등록하는 방법은 크게 두 가지가 있습니다.
- 스프링 부트에서
@Component
어노테이션을 사용하여 필터를 자동으로 등록하는 방법 FilterRegistrationBean
을 사용하여 프로그래매틱하게 필터를 등록하는 방법
1. @Component
어노테이션을 사용한 필터 등록
가장 간단한 방법은 필터 클래스에 @Component
어노테이션을 붙여서 스프링이 필터를 자동으로 감지하고 등록하도록 하는 것입니다.
예시: ClientFilter
등록
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component // 필터를 스프링 애플리케이션에 자동으로 등록
public class ClientFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
Client client = new Client(1, "John Doe"); // 가상의 Client 객체 생성
httpRequest.setAttribute("client", client); // 요청 속성에 Client 객체 저장
chain.doFilter(request, response); // 필터 체인 실행
}
@Override
public void destroy() {}
}
@Component
: 이 어노테이션을 붙이면, 스프링이 이 클래스를 자동으로 빈(bean)으로 등록하고, 서블릿 필터로도 자동으로 설정됩니다.- 필터가 등록된 이후, 모든 HTTP 요청은 이 필터를 거치게 됩니다.
2. FilterRegistrationBean
을 사용한 프로그래매틱 필터 등록
두 번째 방법은 FilterRegistrationBean
을 사용하여 프로그래매틱하게 필터를 등록하는 방법입니다. 이를 통해 필터의 우선순위, 특정 경로에만 필터 적용 등의 설정을 할 수 있습니다.
예시: FilterRegistrationBean
을 사용한 필터 등록
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<ClientFilter> clientFilter() {
FilterRegistrationBean<ClientFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new ClientFilter());
registrationBean.addUrlPatterns("/client/*"); // 필터가 적용될 URL 패턴 설정
registrationBean.setOrder(1); // 필터의 우선순위 설정 (낮을수록 높은 우선순위)
return registrationBean;
}
}
코드 설명:
@Configuration
: 이 클래스는 스프링의 설정 클래스임을 나타냅니다.FilterRegistrationBean
: 이 빈을 사용해 필터를 등록하고 설정할 수 있습니다.setFilter(new ClientFilter())
: 직접 필터 인스턴스를 설정합니다.addUrlPatterns("/client/*")
: 필터가 적용될 URL 패턴을 지정할 수 있습니다. 이 예제에서는/client/*
경로에만 필터가 적용됩니다.setOrder(1)
: 필터의 우선순위를 설정할 수 있습니다. 숫자가 낮을수록 우선순위가 높습니다.
필터 적용 대상 설정
필터는 특정 URL 패턴에만 적용되거나, 특정 경로를 제외하도록 설정할 수 있습니다. 예를 들어, addUrlPatterns
또는 addInitParameter
를 사용하여 필터가 적용될 경로를 지정할 수 있습니다.
registrationBean.addUrlPatterns("/api/*"); // "/api/*" 경로에만 필터 적용
필터 적용 순서 설정
여러 필터가 존재할 경우, 필터의 순서를 제어할 수 있습니다. 필터의 순서는 setOrder()
메서드로 설정하며, 숫자가 낮을수록 높은 우선순위를 가집니다.
registrationBean.setOrder(1); // 가장 높은 우선순위
필터 등록 요약
@Component
어노테이션을 사용하면 스프링이 필터를 자동으로 등록하고, 모든 요청에 대해 필터를 적용할 수 있습니다.FilterRegistrationBean
을 사용하면 특정 URL 경로에 필터를 적용하거나, 우선순위 등을 설정할 수 있습니다.
필요에 따라 두 방법 중 하나를 선택해서 사용하면 됩니다. @Component
를 사용하는 것이 간단하고 기본적인 설정에 적합하며, FilterRegistrationBean
은 세부적인 필터 설정이 필요할 때 유용합니다.
필터는 스프링 애플리케이션의 요청 처리 파이프라인에서 특정 위치에 존재하며, 서블릿 컨테이너 레벨에서 실행됩니다. 즉, 필터는 서블릿이나 스프링의 컨트롤러가 실행되기 전에 요청을 가로채고, 응답이 돌아오기 전에 후처리할 수 있습니다.
필터의 위치
필터는 서블릿 컨테이너(예: Tomcat)에서 동작하는 구조이므로, 스프링 애플리케이션의 요청 처리 과정 중 다음과 같은 위치에서 실행됩니다.
- DispatcherServlet 이전: 모든 HTTP 요청이 필터를 거쳐서 스프링의
DispatcherServlet
으로 전달됩니다. 필터는 이 과정에서 요청을 가로채거나 수정할 수 있으며,DispatcherServlet
이 실행되기 전(또는 후)에 특정 로직을 수행할 수 있습니다. - 인터셉터보다 먼저 실행: 스프링의 HandlerInterceptor보다 먼저 실행됩니다. 필터는 컨트롤러에 요청이 도달하기 전에 요청을 처리하거나 변경할 수 있는 위치에 있습니다.
- 서블릿과 비즈니스 로직에 독립적: 필터는 서블릿이나 컨트롤러 로직과는 독립적으로 동작합니다. 필터가 설정된 경로에 대해 모든 요청을 처리할 수 있으며, 보안, 인증, 로깅, 데이터 압축 등 다양한 목적으로 사용됩니다.
스프링 요청 처리 과정에서 필터의 위치
- 클라이언트 요청: 브라우저 또는 클라이언트가 HTTP 요청을 보냅니다.
- 필터: 서버는 먼저 필터 체인을 통해 요청을 전달합니다. 필터는 이 단계에서 요청을 가로채고, 수정하거나 추가적인 작업을 할 수 있습니다.
- DispatcherServlet: 필터를 통과한 요청은 스프링의
DispatcherServlet
으로 전달됩니다. - HandlerInterceptor:
DispatcherServlet
에서 컨트롤러로 요청을 전달하기 전, 인터셉터가 요청을 가로채고 추가 처리를 할 수 있습니다. - 컨트롤러: 마지막으로 요청은 스프링의 컨트롤러로 전달되어, 비즈니스 로직을 수행하고 응답을 반환합니다.
- 응답 처리: 응답이 클라이언트로 돌아가는 과정에서도 필터가 다시 실행되어 응답을 처리할 수 있습니다.
필터의 실행 흐름
- 요청(Request): 필터는 HTTP 요청이 서버에 도착할 때 제일 먼저 실행됩니다. 필터는 요청을 수정하거나, 인증/인가 처리, 로깅 등을 수행할 수 있습니다.
- 응답(Response): 컨트롤러에서 처리된 응답이 클라이언트로 돌아가기 전에, 필터는 응답을 다시 가로채서 수정하거나, 추가적인 처리를 할 수 있습니다. 예를 들어, 응답을 압축하거나, 헤더를 추가하는 작업을 할 수 있습니다.
필터 체인
필터는 체인(chain) 구조로 구성되어 있으며, 여러 필터가 있는 경우 차례대로 실행됩니다. 하나의 필터가 완료되면 다음 필터가 실행되며, 모든 필터가 실행된 후 요청은 최종적으로 DispatcherServlet
또는 컨트롤러로 전달됩니다.
필터 체인의 흐름
- 요청이 필터 A를 통과
- 요청이 필터 B를 통과
- 요청이 필터 C를 통과
- 요청이
DispatcherServlet
으로 전달되어 컨트롤러로 이동 - 응답이 다시 필터 C, B, A 순으로 역순으로 돌아가면서 처리됨
- 최종 응답이 클라이언트로 전송됨
필터의 주요 사용 사례
- 인증 및 인가: 필터는 사용자 요청을 가로채 인증 및 인가(Authorization) 로직을 처리할 수 있습니다. 예를 들어, 특정 경로에 접근하려면 로그인이 필요한지 확인할 수 있습니다.
- 로깅 및 모니터링: 모든 요청에 대해 로그를 남기거나, 성능 모니터링을 위한 데이터를 수집할 수 있습니다.
- 데이터 압축 및 암호화: 응답 데이터에 대해 압축 또는 암호화를 적용할 수 있습니다.
- CORS 처리: 크로스 도메인 요청(Cross-Origin Resource Sharing, CORS)을 허용하거나 제한하는 데 필터가 사용될 수 있습니다.
필터의 실행 순서 설정
필터의 순서는 FilterRegistrationBean
을 사용하여 설정할 수 있으며, 이를 통해 필터의 우선순위를 조정할 수 있습니다.
registrationBean.setOrder(1); // 우선순위 1로 설정 (숫자가 낮을수록 우선 실행)
- 여러 필터가 있는 경우
setOrder()
메서드를 통해 우선순위를 지정할 수 있으며, 낮은 숫자일수록 더 먼저 실행됩니다.
Summary
- 필터는 서블릿 컨테이너 레벨에서 동작하며, 요청이
DispatcherServlet
이나 컨트롤러에 도달하기 전에 실행됩니다. - 필터는 인증/인가, 로깅, 데이터 처리, 보안 등의 작업을 수행할 수 있으며, 요청과 응답을 모두 처리할 수 있습니다.
- 필터는 체인 구조로 실행되며, 순서에 따라 필터가 실행된 후 최종적으로 컨트롤러로 요청이 전달됩니다.
'Spring Framework > Web on Servlet Stack' 카테고리의 다른 글
Handler Method : Flash Attributes (0) | 2024.10.09 |
---|---|
Handler Method : Redirect Attributes (0) | 2024.10.09 |
Handler Method : @RequestAttribute (0) | 2024.10.09 |
Handler Method : @SessionAttribute (0) | 2024.10.09 |
Handler Method : @SessionAttributes (6) | 2024.10.09 |