Controller에서 Request Body를 읽지 못하는 문제 해결 - Interceptor를 통한 RequestBody 로그 시도인 경우

2025. 4. 6. 14:56·IT 기술/Spring boot

Controller에서 Request Body를 읽지 못하는 문제 해결

Interceptor를 통한 RequestBody 로깅 시 발생하는 문제와 해결 방법

Spring Boot 프로젝트를 진행하면서 Interceptor를 사용해 요청과 응답을 로깅하는 경우가 많습니다. 특히, API 요청 시 Request Body를 로그에 남기는 것은 디버깅과 모니터링에 큰 도움이 됩니다. 그러나 때로는 Interceptor에서 Request Body를 읽으려다 Controller에서 다시 Request Body를 읽지 못하는 문제가 발생합니다. 이 글에서는 이러한 현상의 원인과 효과적인 해결 방법을 알아보겠습니다.

문제의 원인

Spring MVC에서 Request Body를 읽는 방법인 HttpServletRequest의 InputStream은 한 번만 읽을 수 있습니다. Interceptor나 Filter에서 이미 InputStream을 읽었다면, Controller에서는 다시 읽을 수 없는 상태가 되어 버립니다. 이로 인해 Controller에서 @RequestBody로 데이터를 바인딩하려고 하면 빈 값이나 에러가 발생합니다.

문제 상황 예시

Interceptor에서 다음과 같은 코드로 Request Body를 로깅했다고 가정해 봅시다.

@Component
public class RequestBodyLoggingInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        String body = StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8);
        log.info("Request Body: {}", body);
        return true;
    }
}

위의 코드를 사용하면 InputStream이 비워져, Controller에서 RequestBody 데이터를 읽지 못하게 됩니다.

해결 방법: ContentCachingRequestWrapper 사용

이 문제를 해결하는 가장 효과적인 방법은 Spring에서 제공하는 ContentCachingRequestWrapper를 사용하는 것입니다. 이 클래스는 요청 내용을 캐시하고 여러 번 읽을 수 있도록 도와줍니다.

해결 예시 코드

다음과 같이 Interceptor 대신 Filter를 사용하여 ContentCachingRequestWrapper로 Request를 래핑합니다.

@Component
public class RequestBodyLoggingFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
        filterChain.doFilter(wrappedRequest, response);

        String requestBody = new String(wrappedRequest.getContentAsByteArray(), StandardCharsets.UTF_8);
        log.info("Request Body: {}", requestBody);
    }
}

이렇게 하면 요청이 Controller에 도달하기 전에 이미 읽힌 InputStream이 캐시되어 다시 읽을 수 있는 상태로 전달됩니다.

주의사항

  • Filter의 순서가 중요합니다. ContentCachingRequestWrapper를 적용하는 Filter는 Request Body를 읽는 다른 Filter보다 앞에 위치해야 합니다.
  • 로깅은 성능에 영향을 줄 수 있으므로, 프로덕션 환경에서는 로깅 레벨을 잘 관리하거나 일부 요청에 대해서만 로깅을 수행하도록 설정하는 것이 좋습니다.
  • HttpServletRequestWrapper를 활용한 로깅 방법도 있습니다.

정리

Interceptor에서 Request Body를 로깅할 때 발생하는 문제는 InputStream의 일회성 특성 때문입니다. ContentCachingRequestWrapper를 사용하면 Request Body를 여러 번 읽을 수 있게 하여 문제를 간단히 해결할 수 있습니다. 이 방법을 활용하면 보다 효율적으로 API 요청을 로깅하고 디버깅할 수 있습니다.

'IT 기술 > Spring boot' 카테고리의 다른 글

Spring vs Spring Boot: 차이점과 선택 기준  (1) 2025.03.18
Spring Boot에서 Security 적용 시 H2 Console(/h2-console) 접근 불가 문제 해결 방법  (0) 2025.03.05
Connection Pool과 @Transactional: 효율적인 데이터베이스 관리를 위한 핵심 개념  (0) 2025.02.25
/gradlew bootRun은 어떻게 동작하는가?  (1) 2025.02.22
'IT 기술/Spring boot' 카테고리의 다른 글
  • Spring vs Spring Boot: 차이점과 선택 기준
  • Spring Boot에서 Security 적용 시 H2 Console(/h2-console) 접근 불가 문제 해결 방법
  • Connection Pool과 @Transactional: 효율적인 데이터베이스 관리를 위한 핵심 개념
  • /gradlew bootRun은 어떻게 동작하는가?
시남
시남
개발하는 사람입니다. 하고 싶은 것들 사이에서 매번 선택하는 삶을 살고 있습니다.
  • 시남
    Refactor Life like code.
    시남
  • 전체
    오늘
    어제
    • 분류 전체보기 (22)
      • IT 기술 (10)
        • Spring boot (5)
      • 이야기 (3)
      • 독서 (0)
      • 개발일기 (4)
        • 1D3Q (4)
  • 블로그 메뉴

    • 홈
    • 태그
    • 미디어로그
    • 위치로그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    springboot h2
    로켓방정식의 저주
    bootrun
    기획
    H2DB
    Ai
    리버스 터널링
    vibe coding
    프롬프트 엔지니어링
    1인기획
    사이드프로젝트
    ai 검색
    h2 console
    Spring Boot
    gemini
    root@localhost
    contentcachingrequestwrapper
    h2 콘솔
    1D3Q
    AWS
    reverse tunnel
    java
    1인개발
    h2-console
    gradle-wrapper
    개발일지
    Spring
    회고
    코드 하이라이팅
    바이브코딩
  • 최근 댓글

  • 최근 글

  • hELLO By정상우.v4.10.4 관리
시남
Controller에서 Request Body를 읽지 못하는 문제 해결 - Interceptor를 통한 RequestBody 로그 시도인 경우
상단으로

티스토리툴바