에러 커스텀 리팩토링 작업을 하다가
Spring Security의 요청 처리 단계는 MVC 요청 처리 흐름보다 앞서 있다는 사실을 알았고,
이런 처리를 명확하게 하기 위해서는
요청 처리 흐름에 대해 조금 더 자세히 정리해 둬야 겠다는 생각이 들었다.
먼저 Spring Framework의 간략한 요청 흐름은 다음과 같다.
🐣요청 흐름
- 클라이언트 → Filter: 요청 가공, 인증 토큰 확인 등.
- → DispatcherServlet: 요청 라우팅 중심.
- → Interceptor (preHandle): 컨트롤러 실행 전 공통 작업.
- → Handler (Controller): 요청 처리.
- → Interceptor (postHandle): 컨트롤러 실행 후 응답 수정 가능.
- → View: 응답 렌더링.
- → Interceptor (afterCompletion): 뷰 렌더링 후 마무리 작업.
- → Filter: 응답 수정 후 반환.
- → 클라이언트: 최종 응답 반환.
하나 하나 자세히 보자
클라이언트 요청
클라이언트(브라우저, REST 클라이언트 등)가 HTTP 요청을 보낸다.
ex) GET /users 또는 POST /users.
서블릿 컨테이너(예: 톰캣)가 요청을 받아 스프링의 DispatcherServlet에 전달
DispatcherServlet
중앙 컨트롤러 역할: 모든 요청과 응답은 DispatcherServlet을 통해 흐른다.
각 구성 요소(HandlerMapping, HandlerAdapter, ViewResolver 등)를 조합하여 요청과 응답을 관리한다.
HandlerMapping
DispatcherServler이 얘를 호출하여 요청 url에 따라 요청을 처리할 적절한 핸들러(Controller) 찾음
(스프링 부트에서는 주로 @RequestMapping, @GetMapping, @PostMapping 등의 애노테이션으로 매핑)
HandlerAdapter
매핑된 핸들러(컨트롤러)를 실행하기 위해 HandlerAdapter가 호출된다.
HandlerAdapter는 요청을 실제 핸들러 메서드에 맞게 변환하고 실행하는 역할을 한다.
Handler(Controller)
DispatcherServlet은 컨트롤러의 메서드를 호출하여 요청을 처리합니다.
컨트롤러 메서드는 비즈니스 로직을 실행하거나 필요한 데이터를 생성합니다.
예: 데이터베이스에서 사용자 정보 조회, 서비스 호출, 폼 데이터 검증 등.
ViewResolver(선택)
컨트롤러에서 반환한 뷰 이름(String)을 기반으로, 어떤 뷰를 렌더링할지 결정
결정된 뷰는 View 객체에 의해 렌더링된다.
JSP, Thymeleaf, Mustache 등의 템플릿 엔진이 이 과정에서 사용될 수 있다.
REST API 응답인 경우, @ResponseBody 또는 ResponseEntity로 JSON/XML로 변환된다.
ex) InternalResourceViewResolver는 뷰 이름을 실제 JSP 파일 경로로 매핑.
응답 반환
최종 렌더링된 HTML, JSON, XML 등의 응답이 HTTP 응답으로 클라이언트에 반환된다.
🐣추가 요소
Filter
- DispatcherServlet 이전에 요청을 가로채 처리할 수 있는 서블릿 필터이다.
- 인증, 로깅, 인코딩 처리 등에 사용된다.
- 스프링이 아닌 서블릿 컨테이너 레벨에서 동작한다.
- 모든 요청을 처리할 수 있으나, 스프링의 특정 요청 매핑과는 독립적.
ex ) doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
chain.doFilter()를 호출하여 요청을 다음 필터 또는 DispatcherServlet으로 전달.
Interceptor (HandlerInterceptor)
- 컨트롤러(Controller)의 '핸들러(Handler)'를 호출하기 전과 후에 요청과 응답을 참조하거나 가공할수 있는 일종의 필터
- 스프링 MVC의 Handler(컨트롤러 메서드)와 연관되어 동작하며, DispatcherServlet 이후에 요청을 처리
- 요청 전후에 추가 작업(인증, 권한 확인, 로깅, 공통 비즈니스 로직)을 삽입할 수 있다.
- 스프링 HandlerMapping 및 HandlerAdapter와 밀접하게 동작.
- preHandle, postHandle, afterCompletion 메서드로 구현.
ExceptionResolver
- 요청을 처리하던 중 핸들러(Controller)가 예외를 던졌을 때 DispatcherServlet이 이를 감지하고 HandlerExceptionResolver를 실행
- Spring에서 기본 제공되는 예외 처리 메커니즘 중 하나이다.
- RuntimeException을 포함한 다양한 예외를 처리할 수 있다.
- 예외를 적절한 뷰나 HTTP, JSON 응답으로 변환한다.
ExceptionHandlerExceptionResolver
@ExceptionHandler를 처리한다.
ResponseStatusExceptionResolver
Http상태 코드를 지정해준다.
DefaultHandlerExceptionResolver
스프링 내부 기본 예외를 처리한다.
필터와 인터셉터 차이는 주요하게 다뤄지니 여기서 한번 더 정리
🐣Security vs. MVC Exception
돌아와서 Security에 대한 얘기를 해보자면
- 왜 Security는 별도로 처리될까?
- 요청 처리의 순서상, Security는 Spring MVC보다 앞에서 실행되며 인증/권한 문제를 필터링하기 때문에 예외 처리도 별도로 수행된다.
- Security와 MVC 예외 처리 통합은 가능할까?
- Spring Security에서 예외를 던져 Spring MVC의 예외 처리기로 넘기는 방식으로 통합할 수 있다.
- 하지만 권장되는 방식은 AuthenticationEntryPoint와 AccessDeniedHandler를 활용하여 보안 관련 예외를 독립적으로 처리하는 것이다.
security와 일반 MVC 예외 처리 방식 차이는 다음과 같다.
🐣Security 예외 처리
Security는 Spring의 요청 처리 파이프라인에서 컨트롤러 이전에 실행된다.
따라서 인증이나 권한 문제로 인해 요청이 컨트롤러에 도달하지 못하는 경우, Security 자체가 예외를 처리해야 한다.
이를 위해 Spring Security는 두 가지 주요 예외 처리 컴포넌트를 제공한다:
AuthenticationEntryPoint: 인증 실패 처리 (401 Unauthorized).
AccessDeniedHandler: 권한 부족 처리 (403 Forbidden).
물론, 커스텀 가능하다.
https://develoyummer.tistory.com/158
🐣Spring MVC 예외 처리
Security를 통과한 요청만 컨트롤러에 도달하므로,
컨트롤러나 서비스 계층에서 발생하는 예외는 일반적으로 Spring MVC 예외 처리 메커니즘(@RestControllerAdvice,@ExceptionHandler)을 사용하여 처리된다.
정리하다보니 이것저것 알아보고 싶어져서 중구난방한거같긴 하지만, 그래도 이번 기회에 요청 흐름을 한번 정리할 수 있어서 좋았다.
참고
https://popo015.tistory.com/115
'Spring' 카테고리의 다른 글
[Spring] Filter vs. Interceptor (1) | 2024.11.27 |
---|---|
[Spring Security] 401, 403 에러처리(Spring 3.xx) (13) | 2024.11.26 |
Spring 프로젝트에서 웹소켓 적용하기~!! 2탄 (3) | 2024.06.12 |
Spring 프로젝트에서 웹소켓 적용하기~!! 1탄 (5) | 2024.06.10 |
Google Oauth2 (0) | 2024.04.02 |