Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Not getting response body when using ContentCachingResponseWrapper

I have a Spring Boot API in Scala with multiple endpoints. All endpoints are async and return DeferredResult. I want to use filters to log response body in some cases. I have created a filter with order 1 to cache requests and response as below:

@Component
@Order(1)
class ContentCachingFilter extends OncePerRequestFilter {
  override def doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain): Unit = {
    val requestToCache  = new ContentCachingRequestWrapper(request)
    val responseToCache = new ContentCachingResponseWrapper(response)
    filterChain.doFilter(requestToCache, responseToCache)
    responseToCache.copyBodyToResponse()
  }
}

My logging filter is similar to below (removed domain specific logic):

@Component
@Order(2)
class RequestResponseLoggingFilter extends OncePerRequestFilter {

  override def doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain): Unit = {

    logger.info(
      s"Request -> URL : ${request.getMethod} ${request.getRequestURI} ${request.getParameterMap.asScala.stringRepresentation()}")
    logger.debug(
      s"Request Headers -> Content-type : ${request.getContentType} \\n Headers : ${new ServletServerHttpRequest(request).getHeaders}")

    filterChain.doFilter(request, response)

    logger.info(s"Response -> Status : ${response.getStatus}")

  }
}

I have to use ContentCachingResponseWrapper because I want to log the response body. However, even without trying to log the response body and just by introducing ContentCachingResponseWrapper, I don't get any response for calls to any endpoint. A local running instance returns an output like this on curl:

HTTP/1.1 200
Content-Type: application/json
Content-Length: 197
.
.
.
<
* transfer closed with 197 bytes remaining to read
* stopped the pause stream!
* Closing connection 0
curl: (18) transfer closed with 197 bytes remaining to read

If I remove the ContentCachingFilter, the logging filter above works fine but if I try to log response body, the response stream is consumed and the response is no longer generated. Hence I need to use ContentCachingFilter.

I did find out that all this works if the endpoints are synchronous. Could someone help me find out what is the problem and how to make this work with asynchronous endpoint?

like image 540
nishantv Avatar asked Jul 18 '26 10:07

nishantv


1 Answers

responseToCache.copyBodyToResponse()

change to :

if (requestToCache.isAsyncStarted()) {
  requestToCache.getAsyncContext().addListener(new AsyncListener() {
      public void onComplete(AsyncEvent asyncEvent) throws IOException {
          responseToCache.copyBodyToResponse()
      }

      public void onTimeout(AsyncEvent asyncEvent) throws IOException {
      }

      public void onError(AsyncEvent asyncEvent) throws IOException {
      }

      public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
      }
  })
} else {
  responseToCache.copyBodyToResponse()
}

like image 92
linys Avatar answered Jul 20 '26 06:07

linys