2016-10-08 5 views
15

Ich versuche, Filter für Protokollierungsanforderungen und Antworten in Spring MVC Anwendung zu implementieren. Ich verwende den folgenden Code ein:ContentCachingResponseWrapper erzeugt leere Antwort

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

Also, ich meine Anfrage und respone erhalten angemeldet wie erwartet. Hier sind die Protokolle:

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

Die leere Antwort wird jedoch zurückgegeben. Hier ist die Ausgabe von 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 

Irgendwelche Ideen?

Dank

Antwort

18

Nach paar Stunden zu kämpfen, habe ich endlich die Lösung gefunden.

Kurz gesagt, ContentCachingResponseWrapper.copyBodyToResponse() sollte am Ende der Filtermethode aufgerufen werden.

ContentCachingResponseWrapper speichert den Antworttext, indem er ihn aus dem Antwortausgangsstrom liest. Der Stream wird also leer. Um die Antwort zurück auf den Ausgangsstrom zu schreiben, sollte ContentCachingResponseWrapper.copyBodyToResponse() verwendet werden.

+2

sie dies zu javadoc von ContentCachingResponseWrapper hinzufügen sollten – lpandzic

1

Schließlich löste das Problem. Hier ist die perfekte Lösung:

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

Wie haben Sie diesen Filter – user2478236

+1

@Component Annotation registrieren automatisch diesen Filter registrieren. –

+0

Ich habe eine leere "String requestBody" auch mit dieser Methode ... –