728x90
problem
요청처리가 완료된 후 ServletRequest 의 body 를 log 로 남기려고 했다.
ServletRequest 는 inputStream 이므로 한번 밖에 읽을 수 없다.
Controller 는 RequestBody 로 서블릿 request 를 읽는다.
그래서 인터셉터로 구현한 log인터셉터에서 body 가 빈값으로 들어오는 것이었다.
검색해보니 ContentCachingRequestWrapper 로 request를 래핑 해주라는 말이 있었는데
ContentCachingRequestWrapper(request)
필터에서 래핑해줘도 스프링시큐리티에서
Servlet3SecurityContextHolderAwareRequestWrapper 클래스로 래핑해서 컨트롤러에 전달하는 상황이 발생했다.
solution
request 를 래핑해주는 커스텀 필터를 만들어 주었다.
CachedHttpServletRequest 구현
class CachedHttpServletRequest(request: HttpServletRequest) : HttpServletRequestWrapper(request) {
private val cachedByteArray: ByteArray = StreamUtils.copyToByteArray(request.inputStream)
override fun getInputStream(): ServletInputStream {
return CachedBodyServletInputStream(cachedByteArray)
}
override fun getReader(): BufferedReader {
val byteArrayInputStream = ByteArrayInputStream(cachedByteArray)
return BufferedReader(InputStreamReader(byteArrayInputStream))
}
private class CachedBodyServletInputStream(private val cachedBody: ByteArray) : ServletInputStream() {
private val cachedBodyInputStream: InputStream = ByteArrayInputStream(cachedBody)
override fun isFinished(): Boolean {
return try {
cachedBodyInputStream.available() == 0
} catch (e: IOException) {
throw RuntimeException("[CachedBodyServletInputStream] cachedBodyInputStream available fail", e)
}
}
override fun isReady(): Boolean = true
override fun setReadListener(readListener: ReadListener?) {
throw UnsupportedOperationException()
}
@Throws(IOException::class)
override fun read(): Int {
return cachedBodyInputStream.read()
}
}
}
request 를 읽은 후 데이터를 복사 해주어 저장해둔다.
RequestCacheFilter 구현
@Component
class RequestCacheFilter : OncePerRequestFilter() {
@Throws(ServletException::class, IOException::class)
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
val cachedBodyHttpServletRequest = CachedHttpServletRequest(request)
filterChain.doFilter(cachedBodyHttpServletRequest, response)
}
}
필터를 이용하여 서블릿 리퀘스트가 요청 마다 작동 할 수 있도록 만들어 준다.
728x90
'개-발 > Java + Spring + Kotlin' 카테고리의 다른 글
[Spring] NCP SMS 인증번호 시스템 구현 (1) | 2024.12.03 |
---|---|
[Spring] 상대방 채팅 읽음 감지 (1) | 2024.11.17 |
[spring] Cache 조회 성능을 최적화 Redis + Kotlin (0) | 2024.11.14 |
[WebSoket] Spring + SocketJs 사용하기 ( 테스트 Html코드 공유 ) (0) | 2024.11.02 |
[Spring Batch] 반복 오류 제어 (0) | 2024.09.01 |