Spring Boot 使用ContentCachingResponseWrapper时未获取响应正文

ilmyapht  于 2023-02-04  发布在  Spring
关注(0)|答案(3)|浏览(992)

我在Scala中有一个带多个端点的Springboot API。所有端点都是异步的,返回DeferredResult。在某些情况下,我想使用过滤器记录响应主体。我创建了一个顺序为1的过滤器来缓存请求和响应,如下所示:

@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()
  }
}

我的日志过滤器类似于下面的内容(删除了域特定逻辑):

@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}")

  }
}

我必须使用ContentCachingResponseWrapper,因为我想记录响应主体,但是,即使不尝试记录响应主体,而只是引入ContentCachingResponseWrapper,我也不会得到任何端点调用的响应。

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

如果我删除ContentCachingFilter,上面的日志过滤器可以正常工作,但是如果我尝试记录响应主体,响应流将被消耗,并且不再生成响应。
我确实发现如果端点是同步的,所有这些都可以工作。有没有人能帮我找出问题所在,以及如何使异步端点工作。

kpbpu008

kpbpu0081#

responseToCache.copyBodyToResponse()

变更为:

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()
}
ycl3bljg

ycl3bljg2#

val requestToCache = new ContentCachingRequestWrapper(request);
val responseToCache = new ContentCachingResponseWrapper(response);

这两行更改为:

if(!(request instanceof ContentCachingRequestWrapper)) {
     requestToCache = new ContentCachingRequestWrapper(request);
  }
  if(!(request instanceof ContentCachingResponseWrapper)){
     responseToCache = new ContentCachingResponseWrapper(request);
  }
ct3nt3jp

ct3nt3jp3#

我遇到了同样的问题,添加ContentCachingResponseWrapper后没有http响应。这是一个顺序问题,一旦我改变了调用顺序,一切都按预期工作。下一个块是错误的方式,导致症状

ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);
wrappedResponse.copyBodyToResponse();
filterChain.doFilter(wrappedRequest, wrappedResponse);

这是解决我问题的命令。

ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);
filterChain.doFilter(wrappedRequest, wrappedResponse);
wrappedResponse.copyBodyToResponse();

相关问题