2016-10-08 10 views
15

Próbuję zaimplementować filtr do rejestrowania żądań i odpowiedzi w aplikacji Spring MVC. używam następujący kod:ContentCachingResponseWrapper tworzy pustą odpowiedź

@Component 
public class LoggingFilter extends OncePerRequestFilter { 

    private static final Logger LOGGER = LoggerFactory.getLogger(LoggingFilter.class); 

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

     ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request); 
     ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response); 

     LOGGER.debug(REQUEST_MESSAGE_FORMAT, requestWrapper.getRequestURI(), requestWrapper.getMethod(), requestWrapper.getContentType(), 
       new ServletServerHttpRequest(requestWrapper).getHeaders(), IOUtils.toString(requestWrapper.getInputStream(), UTF_8)); 

     filterChain.doFilter(requestWrapper, responseWrapper); 

     LOGGER.debug(RESPONSE_MESSAGE_FORMAT, responseWrapper.getStatus(), responseWrapper.getContentType(), 
       new ServletServerHttpResponse(responseWrapper).getHeaders(), IOUtils.toString(responseWrapper.getContentInputStream(), UTF_8)); 
    } 
} 

Tak, mam moją prośbę i respone rejestrowane zgodnie z oczekiwaniami. Oto dzienniki:

2016-10-08 19:10:11.212 DEBUG 11072 --- [qtp108982313-19] by.kolodyuk.logging.LoggingFilter 
---------------------------- 
ID: 1 
URI: /resources/1 
Http-Method: GET 
Content-Type: null 
Headers: {User-Agent=[curl/7.41.0], Accept=[*/*], Host=[localhost:9015]} 
Body: 
-------------------------------------- 
2016-10-08 19:10:11.277 DEBUG 11072 --- [qtp108982313-19] by.kolodyuk.logging.LoggingFilter 
---------------------------- 
ID: 1 
Response-Code: 200 
Content-Type: application/json;charset=UTF-8 
Headers: {} 
Body: {"id":"1"} 
-------------------------------------- 

Jednak pusta odpowiedź jest zwracana. Oto dane wyjściowe z curl:

$ curl http://localhost:9015/resources/1 --verbose 
* Trying ::1... 
* Connected to localhost (::1) port 9015 (#0) 
> GET /resources/1 HTTP/1.1 
> User-Agent: curl/7.41.0 
> Host: localhost:9015 
> Accept: */* 
> 
< HTTP/1.1 200 OK 
< Date: Sat, 08 Oct 2016 17:10:11 GMT 
< Content-Type: application/json;charset=UTF-8 
< Content-Length: 0 
< 
* Connection #0 to host localhost left intact 

Wszelkie pomysły?

Dzięki

Odpowiedz

18

Po kilku godzinach zmagań, mam w końcu znaleźć rozwiązanie.

W skrócie, ContentCachingResponseWrapper.copyBodyToResponse() powinien zostać wywołany na końcu metody filtra.

ContentCachingResponseWrapper buforuje treść odpowiedzi, odczytując ją ze strumienia wyjściowego odpowiedzi. Strumień staje się pusty. Aby użyć odpowiedzi do strumienia wyjściowego ContentCachingResponseWrapper.copyBodyToResponse() należy użyć.

+2

powinni dodać do javadoc z ContentCachingResponseWrapper – lpandzic

1

W końcu rozwiązano problem. Oto idealne rozwiązanie:

import com.fasterxml.jackson.databind.JsonNode; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import org.apache.commons.io.IOUtils; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.http.*; 
import org.springframework.stereotype.Component; 
import org.springframework.web.filter.OncePerRequestFilter; 
import org.springframework.web.util.ContentCachingRequestWrapper; 
import org.springframework.web.util.ContentCachingResponseWrapper; 

import javax.servlet.FilterChain; 
import javax.servlet.ServletException; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.net.URI; 
import java.util.Enumeration; 
import java.util.Map; 

import static java.nio.charset.StandardCharsets.UTF_8; 
import static net.logstash.logback.marker.Markers.appendFields; 

@Component 
public class LoggingFilter extends OncePerRequestFilter { 

    private static final Logger LOGGER = LoggerFactory.getLogger(LoggingFilter.class); 

    @Autowired 
    private ObjectMapper objectMapper; 

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

    ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(httpServletRequest); 
    ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(httpServletResponse); 

    filterChain.doFilter(requestWrapper, responseWrapper); 

    String requestUrl = requestWrapper.getRequestURL().toString(); 
    HttpHeaders requestHeaders = new HttpHeaders(); 
    Enumeration headerNames = requestWrapper.getHeaderNames(); 
    while (headerNames.hasMoreElements()) { 
     String headerName = (String) headerNames.nextElement(); 
     requestHeaders.add(headerName, requestWrapper.getHeader(headerName)); 
    } 
    HttpMethod httpMethod = HttpMethod.valueOf(requestWrapper.getMethod()); 
    Map<String, String[]> requestParams = requestWrapper.getParameterMap(); 

    String requestBody = IOUtils.toString(requestWrapper.getInputStream(),UTF_8); 
    JsonNode requestJson = objectMapper.readTree(requestBody); 

    RequestEntity<JsonNode> requestEntity = new RequestEntity<>(requestJson,requestHeaders, httpMethod, URI.create(requestUrl)); 
    LOGGER.info(appendFields(requestEntity),"Logging Http Request"); 


    HttpStatus responseStatus = HttpStatus.valueOf(responseWrapper.getStatusCode()); 
    HttpHeaders responseHeaders = new HttpHeaders(); 
    for (String headerName : responseWrapper.getHeaderNames()) { 
     responseHeaders.add(headerName, responseWrapper.getHeader(headerName)); 
    } 
    String responseBody = IOUtils.toString(responseWrapper.getContentInputStream(), UTF_8); 
    JsonNode responseJson = objectMapper.readTree(responseBody); 
    ResponseEntity<JsonNode> responseEntity = new ResponseEntity<>(responseJson,responseHeaders,responseStatus); 
    LOGGER.info(appendFields(responseEntity),"Logging Http Response"); 
    responseWrapper.copyBodyToResponse(); 
    } 
} 
+0

Jak zarejestrować ten filtr – user2478236

+1

@Component adnotacji automatycznie zarejestruje ten filtr. –

+0

Mam pustą "RequestBody String" również z tą metodą ... –