WebFlux 마이그레이션 완료 및 실시간 주식 API 에러 핸들링 대폭 개선

최근 진행하던 Spring Boot WebFlux 기반 프로젝트에서 보안 컴포넌트 호환성 문제실시간 API 에러 추적의 어려움이라는 두 가지 주요 문제를 해결했습니다. 이번 포스팅에서는 WebFlux 환경에 맞게 보안 설정을 전환하고, 디버깅을 위한 로깅 및 에러 핸들링을 어떻게 강화했는지 상세하게 다룹니다.


WebFlux로의 전환과 마주한 문제

WebFlux의 Non-blocking 아키텍처를 도입하여 성능을 향상시키는 과정에서, 기존의 서블릿 기반(Servlet-based) 컴포넌트들이 발목을 잡았습니다. 또한, 핵심 기능인 실시간 주식 데이터 API 엔드포인트(/api/stocks/realtime/{symbol})에서 발생하는 500 Internal Server Error의 원인을 명확히 파악할 수 없어 빠른 해결이 필요했습니다.

발견된 핵심 문제점

구분문제 컴포넌트상세 내용해결 필요성
보안 호환성JwtAuthenticationEntryPointHttpServletRequest, HttpServletResponse서블릿 API 사용WebFlux 환경으로의 전면 전환
보안 호환성JwtAuthenticationFilterOncePerRequestFilter 상속으로 WebFlux와 호환 불가WebFilter 인터페이스로 대체
보안 호환성SecurityConfig서블릿용 CorsConfigurationSource 사용으로 타입 불일치Reactive 타입으로 변경
에러 추적/api/stocks/realtime/{symbol}500 오류 발생 시 로깅 정보 부족으로 원인 파악 불가단계별 상세 로깅예외 체인 추적 강화

WebFlux용 리액티브 보안 컴포넌트로 전환

WebFlux 환경에서는 서블릿 기반의 필터나 엔트리 포인트를 사용할 수 없습니다. 모든 컴포넌트를 리액티브 스트림(Reactive Stream) 패턴에 맞춰 Mono<T> 또는 Flux<T>를 사용하는 방식으로 변경했습니다.

주요 변경 사항

1. JwtAuthenticationEntryPoint 변환 (AuthenticationEntryPointServerAuthenticationEntryPoint)

Before (서블릿)After (WebFlux - Reactive)
AuthenticationEntryPoint 구현ServerAuthenticationEntryPoint 구현
파라미터: HttpServletRequest, HttpServletResponse파라미터: ServerWebExchange, AuthenticationException
반환 타입: void (응답 직접 처리)반환 타입: Mono<Void> (비동기 처리)

이제 ServerWebExchange를 통해 ServerHttpResponse에 접근하고, 응답을 비동기적으로(Non-blocking) 처리하여 Mono<Void>를 반환합니다.

2. JwtAuthenticationFilter 변환 (OncePerRequestFilterWebFilter)

OncePerRequestFilter 대신 WebFlux에서 사용하는 WebFilter 인터페이스를 구현했습니다.

  • WebFilter 사용: HTTP 요청 처리를 리액티브하게 가로채 처리합니다.
  • ReactiveSecurityContextHolder 도입: 서블릿의 SecurityContextHolder 대신, Mono를 통해 비동기적으로 보안 컨텍스트를 저장하고 관리합니다. 모든 작업이 Mono.just().flatMap() 등의 체인으로 구성됩니다.

3. SecurityConfig 수정 및 설정 추가

  • CORS 설정: 서블릿용 CorsConfigurationSourceorg.springframework.web.cors.reactive.CorsConfigurationSource로 변경했습니다.
  • 예외 처리 등록: .exceptionHandling() 설정을 추가하여 JwtAuthenticationEntryPoint인증 엔트리 포인트로 명확하게 등록했습니다.
// SecurityConfig.kt 일부
.exceptionHandling { handling ->
    handling.authenticationEntryPoint(jwtAuthenticationEntryPoint)
}
// ...
// CorsConfigurationSource도 Reactive 타입 사용

실시간 API 에러 핸들링 및 로깅 강화

가장 큰 문제였던 500 에러의 원인 파악을 위해 Python API 클라이언트와 핸들러 레이어의 로깅 수준을 극단적으로 끌어올리고 타입 안전성을 확보했습니다.

'3단계 상세 로깅' 도입

외부 API와의 통신을 담당하는 PythonApiClient에 에러 디버깅을 위한 3단계 로깅 전략을 적용했습니다.

  1. 요청 단계 로깅: 요청을 보내기 직전, 요청 URL심볼 정보INFO 레벨로 로깅합니다.
  2. 응답 단계 로깅: 응답을 받은 후, 응답 데이터 전체를 로깅하여 파싱 전 원본 데이터를 확인합니다.
  3. 파싱 단계 로깅: JSON 응답을 도메인 객체로 변환하는 과정에서 각 필드별 파싱 과정을 상세히 로깅하여, 어떤 필드에서 타입 변환 또는 null 처리 문제가 발생했는지 정확히 추적합니다.

특히, 파싱 에러의 주범이었던 volume 필드에 대해 null 안전성 체크타입 변환 안정화 로직을 추가하여 예외 발생 가능성을 줄였습니다.

예외 체인 로깅

컨트롤러에서 예외를 최종 처리하는 StockHandler에서는 발생한 예외에 대해 타입별 상세 로깅을 추가했습니다.

  • 예외 원인 체인(Cause Chain) 로깅: 단순한 에러 메시지를 넘어, 예외가 발생한 근본적인 원인(Cause)까지 추적하여 로깅하도록 강화했습니다. 이를 통해 파싱 에러가 어디서부터 시작되었는지 쉽게 알 수 있습니다.
  • 명확한 에러 메시지: 각 예외 케이스별로 사용자 및 개발자가 이해하기 쉬운 명확한 에러 메시지를 제공하도록 수정했습니다.

로깅 설정 업데이트 (application.yml)

상세 로깅이 누락되지 않도록 주요 컴포넌트의 로깅 레벨을 조정했습니다.

logging:
  level:
    # API 클라이언트 및 핸들러 로깅 레벨을 INFO로 상향 조정
    com.sleekydz86.backend.infrastructure.client: INFO
    com.sleekydz86.backend.global.handler: INFO

프론트엔드 사용자 경험 향상 에러 처리 개선

서버 측의 에러 핸들링 개선과 더불어, 프론트엔드 dashboard.js에서도 서버 에러 응답을 더욱 상세하게 처리하도록 개선하여 사용자 경험(UX)을 향상시켰습니다.

BeforeAfter
"데이터를 불러올 수 없습니다."라는 단일 메시지 출력서버 응답 상태(Status)상세 데이터를 콘솔에 출력
사용자에게 상세 에러 메시지 표시 (데이터를 불러올 수 없습니다: [서버 에러 메시지])네트워크 오류서버 오류를 구분하여 처리

이를 통해 개발자는 콘솔에서 즉시 서버 상태를 파악할 수 있고, 사용자에게도 보다 명확한 오류 안내가 가능해졌습니다.


WebFlux의 핵심 패턴

이번 마이그레이션을 통해 WebFlux 기반 개발 시 반드시 숙지해야 할 보안 패턴을 다시 한번 확인할 수 있었습니다.

  1. Non-blocking 원칙: 서블릿 API는 절대로 사용하지 않습니다. 모든 컴포넌트와 비즈니스 로직은 MonoFlux를 사용하여 Non-blocking 방식으로 구성해야 합니다.
  2. WebFilter: 요청을 가로채 처리하는 로직(예: JWT 필터)은 WebFilter 구현체를 통해 작성하며, 서블릿의 필터 순서와 마찬가지로 실행 순서를 잘 관리해야 합니다.
  3. Reactive Context: 사용자 인증 정보 등 Context 기반 데이터는 ThreadLocal을 사용하는 서블릿 방식 대신, ReactiveSecurityContextHolder를 통해 관리되어야 합니다.

테스트 체크리스트

상태항목확인 내용
O Spring Boot 서버 시작서버가 WebFlux 환경에서 정상적으로 구동됨
O WebFlux 보안 컴포넌트컴파일 성공 및 WebFilter/ServerAuthenticationEntryPoint 정상 동작 확인
X JWT 인증 필터토큰 유효성 및 인증 로직 정상 동작 확인
X 실시간 API 엔드포인트/api/stocks/realtime/AAPL 정상 응답 확인
X 에러 로깅에러 발생 시 강화된 상세 로그 정상 출력 확인

마이그레이션 및 에러 핸들링 개선 작업을 완료했으며, 현재 최종 테스트 단계에 있습니다.
이 경험이 WebFlux 도입을 고려하는 다른 개발자분들에게 도움이 되길 바랍니다!

profile
에러가 나도 괜찮아 — 그건 내가 배우고 있다는 증거야.

0개의 댓글