spring interceptor에서 http body를 추출할 수 있을까?
spring interceptor는 body를 추출할 수 없다.
- 웹 어플리케이션을 다룰 때 보통 content-type은 application/x-www-form-urlencoded 혹은 application/json을 사용한다. 전자의 key와 value의 묶음인 query parameter는, http method인 get과 post에 관계 없이 컨트롤러와 스프링 인터셉터 등에서 손쉽게 활용 가능하다. 특히 인터셉터에서 파라미터에 대한 로깅을 할 때 효과적으로 사용 가능하다.
- 좀 더 욕심을 내자. 후자인 json을 로그로 남기고 싶었다. 여러 시도를 했지만 결과적으로 실패하였다.
- 실패한 이유와 해결책은 다음 블로그에 잘 정리되어 있다. https://stuffdrawers.tistory.com/9
- 해당 내용을 정리하면 대략 아래와 같다.
filter와 interceptor 사이에 inputStream이 고갈된다.
- body가 interceptor로 넘어오기 전, 스프링은 body 데이터가 있는 inputStream 를 사용하고 close() 한다.
- inputStream을 interceptor에서 사용하기 위해서는 filter에서 해당 데이터를 복제해야 한다. 복제한 데이터를 HttpServletRequest에 넘기고, interceptor는 복제한 객체를 꺼내서 사용한다.
- filter에서 interceptor로 inputStream의 데이터를 전달할 때 사용하는 데이터 타입이 HttpServletRequestWrapper 이다.
스프링은 filter에서 http를 읽을 수 있는 기능을 제공한다.
- (2023.02.16) 바디를 로깅할 수 있으나 다소 복잡한 세팅을 해야 한다고 정리하였다. 최근 기술 블로그를 보며 관련한 필터를 스프링이 제공함을 확인했다. 특별한 세팅 없이 필터에 대한 빈 설정 하나로 바디를 비롯한 http 메시지 전반에 대한 로깅이 가능하다.
- CommonsRequestLoggingFilter에 대한 빈을 등록하고, 해당 필터의 로깅 수준을 DEBUG로 설정한다.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CommonsRequestLoggingFilter;
@Configuration
public class MyFilter {
@Bean
public CommonsRequestLoggingFilter requestLoggingFilter() {
CommonsRequestLoggingFilter loggingFilter = new CommonsRequestLoggingFilter();
loggingFilter.setIncludeClientInfo(true);
loggingFilter.setIncludeHeaders(true);
loggingFilter.setIncludeQueryString(true);
loggingFilter.setIncludePayload(true);
loggingFilter.setMaxPayloadLength(64000);
return loggingFilter;
}
}
- application.yml
logging:
level:
org:
springframework:
web:
filter:
CommonsRequestLoggingFilter: DEBUG
- 출처
- https://www.baeldung.com/spring-http-logging
- https://stackoverflow.com/questions/33744875/spring-boot-how-to-log-all-requests-and-responses-with-exceptions-in-single-pl