it-swarm.com.de

HTTP-Servlet-Anforderung verliert Parameter von POST body nach einmaligem Lesen

Ich versuche, in einem Java Servlet-Filter auf zwei http-Anforderungsparameter zuzugreifen, aber ich war überrascht, dass die Parameter bereits verbraucht wurden! Aus diesem Grund ist sie nicht verfügbar mehr in der Filterkette.

Dies scheint nur dann der Fall zu sein, wenn die Parameter in einem POST request body (z. B. ein Formular zum Senden) vorliegen.

Gibt es eine Möglichkeit, die Parameter zu lesen und NICHT zu verbrauchen?

Bisher habe ich nur diesen Verweis gefunden: Servlet-Filter mit request.getParameter verliert Formulardaten .

Vielen Dank!

73
amuniz

Abgesehen davon besteht eine alternative Möglichkeit zur Lösung dieses Problems darin, die Filterkette nicht zu verwenden und stattdessen eine eigene Interceptor-Komponente zu erstellen, möglicherweise unter Verwendung von Aspekten, die auf den analysierten Anforderungskörper angewendet werden können. Dies ist wahrscheinlich auch effizienter, da Sie die Anforderung InputStream nur einmal in Ihr eigenes Modellobjekt konvertieren.

Ich denke jedoch immer noch, dass es sinnvoll ist, den Anforderungshauptteil mehrmals zu lesen, insbesondere wenn sich die Anforderung durch die Filterkette bewegt. Normalerweise verwende ich Filterketten für bestimmte Vorgänge, die ich auf der HTTP-Ebene beibehalten möchte, und zwar unabhängig von den Dienstkomponenten.

Wie von Will Hartung vorgeschlagen, habe ich dies erreicht, indem ich HttpServletRequestWrapper erweitert, die Anfrage InputStream konsumiert und im Wesentlichen die Bytes zwischengespeichert habe.

public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
  private ByteArrayOutputStream cachedBytes;

  public MultiReadHttpServletRequest(HttpServletRequest request) {
    super(request);
  }

  @Override
  public ServletInputStream getInputStream() throws IOException {
    if (cachedBytes == null)
      cacheInputStream();

      return new CachedServletInputStream();
  }

  @Override
  public BufferedReader getReader() throws IOException{
    return new BufferedReader(new InputStreamReader(getInputStream()));
  }

  private void cacheInputStream() throws IOException {
    /* Cache the inputstream in order to read it multiple times. For
     * convenience, I use Apache.commons IOUtils
     */
    cachedBytes = new ByteArrayOutputStream();
    IOUtils.copy(super.getInputStream(), cachedBytes);
  }

  /* An inputstream which reads the cached request body */
  public class CachedServletInputStream extends ServletInputStream {
    private ByteArrayInputStream input;

    public CachedServletInputStream() {
      /* create a new input stream from the cached request body */
      input = new ByteArrayInputStream(cachedBytes.toByteArray());
    }

    @Override
    public int read() throws IOException {
      return input.read();
    }
  }
}

Jetzt kann der Anforderungshauptteil mehrmals gelesen werden, indem die ursprüngliche Anforderung umbrochen wird, bevor sie durch die Filterkette geleitet wird:

public class MyFilter implements Filter {
  @Override
  public void doFilter(ServletRequest request, ServletResponse response,
        FilterChain chain) throws IOException, ServletException {

    /* wrap the request in order to read the inputstream multiple times */
    MultiReadHttpServletRequest multiReadRequest = new MultiReadHttpServletRequest((HttpServletRequest) request);

    /* here I read the inputstream and do my thing with it; when I pass the
     * wrapped request through the filter chain, the rest of the filters, and
     * request handlers may read the cached inputstream
     */
    doMyThing(multiReadRequest.getInputStream());
    //OR
    anotherUsage(multiReadRequest.getReader());
    chain.doFilter(multiReadRequest, response);
  }
}

Diese Lösung ermöglicht es Ihnen auch, den Anforderungshauptteil über die getParameterXXX -Methoden mehrmals zu lesen, da der zugrunde liegende Aufruf getInputStream() ist, wodurch natürlich die zwischengespeicherte Anforderung InputStream gelesen wird.

Bearbeiten

Für eine neuere Version von ServletInputStream interface. Sie müssen einige weitere Methoden wie isReady, setReadListener usw. implementieren. Lesen Sie hierzu question , wie im Kommentar unten angegeben.

89
pestrella

Ich weiß, ich bin spät dran, aber diese Frage war immer noch relevant für mich und dieser SO Post war einer der Top-Hits in Google. Ich gehe voran und poste meine Lösung in der Hoffnung, dass jemand anderes könnte ein paar Stunden sparen.

In meinem Fall musste ich alle Anfragen und Antworten mit ihren Körpern protokollieren. Mit Spring Framework ist die Antwort eigentlich recht einfach. Verwenden Sie einfach ContentCachingRequestWrapper und ContentCachingResponseWrapper .

import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import Java.io.IOException;

public class LoggingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

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

        try {
            chain.doFilter(requestWrapper, responseWrapper);
        } finally {

            String requestBody = new String(requestWrapper.getContentAsByteArray());
            String responseBody = new String(responseWrapper.getContentAsByteArray());
            // Do not forget this line after reading response content or actual response will be empty!
            responseWrapper.copyBodyToResponse();

            // Write request and response body, headers, timestamps etc. to log files

        }

    }

}
30
Mikk

Die obigen Antworten waren sehr hilfreich, hatten aber nach meiner Erfahrung noch einige Probleme. Auf Tomcat 7-Servlet 3.0 mussten auch getParamter und getParamterValues ​​überschrieben werden. Die Lösung umfasst hier sowohl Get-Query-Parameter als auch den Post-Body. Dies ermöglicht es, die Rohsaite einfach zu bekommen.

Wie die anderen Lösungen verwendet es Apache Commons-Io und Googles Guava.

In dieser Lösung lösen die getParameter * -Methoden keine IOException aus, sondern verwenden super.getInputStream () (um den Body abzurufen), der IOException auslösen kann. Ich fange es und werfe runtimeException. Es ist nicht so schön.

import com.google.common.collect.Iterables;
import com.google.common.collect.ObjectArrays;

import org.Apache.commons.io.IOUtils;
import org.Apache.http.NameValuePair;
import org.Apache.http.client.utils.URLEncodedUtils;
import org.Apache.http.entity.ContentType;

import Java.io.BufferedReader;
import Java.io.ByteArrayInputStream;
import Java.io.ByteArrayOutputStream;
import Java.io.IOException;
import Java.io.InputStreamReader;
import Java.io.UnsupportedEncodingException;
import Java.nio.charset.Charset;
import Java.util.Collections;
import Java.util.LinkedHashMap;
import Java.util.List;
import Java.util.Map;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
 * Purpose of this class is to make getParameter() return post data AND also be able to get entire
 * body-string. In native implementation any of those two works, but not both together.
 */
public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
    public static final String UTF8 = "UTF-8";
    public static final Charset UTF8_CHARSET = Charset.forName(UTF8);
    private ByteArrayOutputStream cachedBytes;
    private Map<String, String[]> parameterMap;

    public MultiReadHttpServletRequest(HttpServletRequest request) {
        super(request);
    }

    public static void toMap(Iterable<NameValuePair> inputParams, Map<String, String[]> toMap) {
        for (NameValuePair e : inputParams) {
            String key = e.getName();
            String value = e.getValue();
            if (toMap.containsKey(key)) {
                String[] newValue = ObjectArrays.concat(toMap.get(key), value);
                toMap.remove(key);
                toMap.put(key, newValue);
            } else {
                toMap.put(key, new String[]{value});
            }
        }
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (cachedBytes == null) cacheInputStream();
        return new CachedServletInputStream();
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    private void cacheInputStream() throws IOException {
    /* Cache the inputStream in order to read it multiple times. For
     * convenience, I use Apache.commons IOUtils
     */
        cachedBytes = new ByteArrayOutputStream();
        IOUtils.copy(super.getInputStream(), cachedBytes);
    }

    @Override
    public String getParameter(String key) {
        Map<String, String[]> parameterMap = getParameterMap();
        String[] values = parameterMap.get(key);
        return values != null && values.length > 0 ? values[0] : null;
    }

    @Override
    public String[] getParameterValues(String key) {
        Map<String, String[]> parameterMap = getParameterMap();
        return parameterMap.get(key);
    }

    @Override
    public Map<String, String[]> getParameterMap() {
        if (parameterMap == null) {
            Map<String, String[]> result = new LinkedHashMap<String, String[]>();
            decode(getQueryString(), result);
            decode(getPostBodyAsString(), result);
            parameterMap = Collections.unmodifiableMap(result);
        }
        return parameterMap;
    }

    private void decode(String queryString, Map<String, String[]> result) {
        if (queryString != null) toMap(decodeParams(queryString), result);
    }

    private Iterable<NameValuePair> decodeParams(String body) {
        Iterable<NameValuePair> params = URLEncodedUtils.parse(body, UTF8_CHARSET);
        try {
            String cts = getContentType();
            if (cts != null) {
                ContentType ct = ContentType.parse(cts);
                if (ct.getMimeType().equals(ContentType.APPLICATION_FORM_URLENCODED.getMimeType())) {
                    List<NameValuePair> postParams = URLEncodedUtils.parse(IOUtils.toString(getReader()), UTF8_CHARSET);
                    params = Iterables.concat(params, postParams);
                }
            }
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
        return params;
    }

    public String getPostBodyAsString() {
        try {
            if (cachedBytes == null) cacheInputStream();
            return cachedBytes.toString(UTF8);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /* An inputStream which reads the cached request body */
    public class CachedServletInputStream extends ServletInputStream {
        private ByteArrayInputStream input;

        public CachedServletInputStream() {
            /* create a new input stream from the cached request body */
            input = new ByteArrayInputStream(cachedBytes.toByteArray());
        }

        @Override
        public int read() throws IOException {
            return input.read();
        }
    }

    @Override
    public String toString() {
        String query = dk.bnr.util.StringUtil.nullToEmpty(getQueryString());
        StringBuilder sb = new StringBuilder();
        sb.append("URL='").append(getRequestURI()).append(query.isEmpty() ? "" : "?" + query).append("', body='");
        sb.append(getPostBodyAsString());
        sb.append("'");
        return sb.toString();
    }
}
4
arberg

Die einzige Möglichkeit wäre, den gesamten Eingabestream selbst im Filter zu konsumieren, den gewünschten Inhalt daraus zu entnehmen, einen neuen Eingabestream für den von Ihnen gelesenen Inhalt zu erstellen und diesen Eingabestream in einen ServletRequestWrapper (oder HttpServletRequestWrapper) einzufügen.

Der Nachteil ist, dass Sie die Nutzlast selbst analysieren müssen. Der Standard stellt Ihnen diese Funktion nicht zur Verfügung.

Nachträge -

Wie gesagt, Sie müssen sich HttpServletRequestWrapper ansehen.

In einem Filter fahren Sie fort, indem Sie FilterChain.doFilter (Request, Response) aufrufen.

Bei einfachen Filtern stimmen Anforderung und Antwort mit denen überein, die an den Filter übergeben wurden. Das muss nicht so sein. Sie können diese durch Ihre eigenen Anfragen und/oder Antworten ersetzen.

HttpServletRequestWrapper wurde speziell entwickelt, um dies zu erleichtern. Sie übergeben ihm die ursprüngliche Anforderung und können dann alle Anrufe abfangen. Sie erstellen eine eigene Unterklasse und ersetzen die Methode getInputStream durch eine eigene. Sie können den Eingabestream der ursprünglichen Anforderung nicht ändern. Stattdessen verfügen Sie über diesen Wrapper und geben Ihren eigenen Eingabestream zurück.

Der einfachste Fall besteht darin, den ursprünglichen Eingabestream für Anforderungen in einem Bytepuffer zu speichern, die gewünschten Aktionen auszuführen und dann einen neuen ByteArrayInputStream aus diesem Puffer zu erstellen. Dies wird in Ihrem Wrapper zurückgegeben, der an die FilterChain.doFilter-Methode übergeben wird.

Sie müssen ServletInputStream als Unterklasse definieren und einen weiteren Wrapper für Ihren ByteArrayInputStream erstellen, aber das ist auch keine große Sache.

4
Will Hartung

Ich hatte auch das gleiche Problem und glaube, der folgende Code ist einfacher und funktioniert für mich.

public class MultiReadHttpServletRequest extends  HttpServletRequestWrapper {

 private String _body;

public MultiReadHttpServletRequest(HttpServletRequest request) throws IOException {
   super(request);
   _body = "";
   BufferedReader bufferedReader = request.getReader();           
   String line;
   while ((line = bufferedReader.readLine()) != null){
       _body += line;
   }
}

@Override
public ServletInputStream getInputStream() throws IOException {
   final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(_body.getBytes());
   return new ServletInputStream() {
       public int read() throws IOException {
           return byteArrayInputStream.read();
       }
   };
}

@Override
public BufferedReader getReader() throws IOException {
   return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
}

in der filter Java class,

            HttpServletRequest properRequest = ((HttpServletRequest) req);
            MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(properRequest);
            req = wrappedRequest;
            inputJson = IOUtils.toString(req.getReader());
            System.out.println("body"+inputJson);

Bitte lassen Sie mich wissen, wenn Sie Fragen haben

3
Lathy

Dies ist also im Grunde Lathys Antwort, ABER aktualisiert für neuere Anforderungen für ServletInputStream.

Nämlich (für ServletInputStream) muss man implementieren:

public abstract boolean isFinished();

public abstract boolean isReady();

public abstract void setReadListener(ReadListener var1);

Dies ist das bearbeitete Lathy's Objekt

import Java.io.BufferedReader;
import Java.io.IOException;
import Java.io.InputStreamReader;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

public class RequestWrapper extends HttpServletRequestWrapper {

    private String _body;

    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        _body = "";
        BufferedReader bufferedReader = request.getReader();
        String line;
        while ((line = bufferedReader.readLine()) != null){
            _body += line;
        }
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {

        CustomServletInputStream kid = new CustomServletInputStream(_body.getBytes());
        return kid;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(this.getInputStream()));
    }
}

und irgendwo (??) habe ich das gefunden (das ist eine erstklassige Klasse, die sich mit den "extra" Methoden befasst.

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import Java.io.IOException;
import Java.io.UnsupportedEncodingException;

public class CustomServletInputStream extends ServletInputStream {

    private byte[] myBytes;

    private int lastIndexRetrieved = -1;
    private ReadListener readListener = null;

    public CustomServletInputStream(String s) {
        try {
            this.myBytes = s.getBytes("UTF-8");
        } catch (UnsupportedEncodingException ex) {
            throw new IllegalStateException("JVM did not support UTF-8", ex);
        }
    }

    public CustomServletInputStream(byte[] inputBytes) {
        this.myBytes = inputBytes;
    }

    @Override
    public boolean isFinished() {
        return (lastIndexRetrieved == myBytes.length - 1);
    }

    @Override
    public boolean isReady() {
        // This implementation will never block
        // We also never need to call the readListener from this method, as this method will never return false
        return isFinished();
    }

    @Override
    public void setReadListener(ReadListener readListener) {
        this.readListener = readListener;
        if (!isFinished()) {
            try {
                readListener.onDataAvailable();
            } catch (IOException e) {
                readListener.onError(e);
            }
        } else {
            try {
                readListener.onAllDataRead();
            } catch (IOException e) {
                readListener.onError(e);
            }
        }
    }

    @Override
    public int read() throws IOException {
        int i;
        if (!isFinished()) {
            i = myBytes[lastIndexRetrieved + 1];
            lastIndexRetrieved++;
            if (isFinished() && (readListener != null)) {
                try {
                    readListener.onAllDataRead();
                } catch (IOException ex) {
                    readListener.onError(ex);
                    throw ex;
                }
            }
            return i;
        } else {
            return -1;
        }
    }
};

Letztendlich habe ich nur versucht, die Anfragen zu protokollieren. Und die oben genannten Stücke haben mir geholfen, das Unten zu erschaffen.

import Java.io.IOException;
import Java.io.UnsupportedEncodingException;
import Java.security.Principal;
import Java.util.Enumeration;
import Java.util.LinkedHashMap;
import Java.util.Map;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.Apache.commons.io.IOUtils;

//one or the other based on spring version
//import org.springframework.boot.autoconfigure.web.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorAttributes;

import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.filter.OncePerRequestFilter;


/**
 * A filter which logs web requests that lead to an error in the system.
 */
@Component
public class LogRequestFilter extends OncePerRequestFilter implements Ordered {

    // I tried Apache.commons and slf4g loggers.  (one or the other in these next 2 lines of declaration */
    //private final static org.Apache.commons.logging.Log logger = org.Apache.commons.logging.LogFactory.getLog(LogRequestFilter.class);
    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(LogRequestFilter.class);

    // put filter at the end of all other filters to make sure we are processing after all others
    private int order = Ordered.LOWEST_PRECEDENCE - 8;
    private ErrorAttributes errorAttributes;

    @Override
    public int getOrder() {
        return order;
    }

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

        String temp = ""; /* for a breakpoint, remove for production/real code */

        /* change to true for easy way to comment out this code, remove this if-check for production/real code */
        if (false) {
            filterChain.doFilter(request, response);
            return;
        }

        /* make a "copy" to avoid issues with body-can-only-read-once issues */
        RequestWrapper reqWrapper = new RequestWrapper(request);

        int status = HttpStatus.INTERNAL_SERVER_ERROR.value();
        // pass through filter chain to do the actual request handling
        filterChain.doFilter(reqWrapper, response);
        status = response.getStatus();

        try {
            Map<String, Object> traceMap = getTrace(reqWrapper, status);
            // body can only be read after the actual request handling was done!
            this.getBodyFromTheRequestCopy(reqWrapper, traceMap);

            /* now do something with all the pieces of information gatherered */
            this.logTrace(reqWrapper, traceMap);
        } catch (Exception ex) {
            logger.error("LogRequestFilter FAILED: " + ex.getMessage(), ex);
        }
    }

    private void getBodyFromTheRequestCopy(RequestWrapper rw, Map<String, Object> trace) {
        try {
            if (rw != null) {
                byte[] buf = IOUtils.toByteArray(rw.getInputStream());
                //byte[] buf = rw.getInputStream();
                if (buf.length > 0) {
                    String payloadSlimmed;
                    try {
                        String payload = new String(buf, 0, buf.length, rw.getCharacterEncoding());
                        payloadSlimmed = payload.trim().replaceAll(" +", " ");
                    } catch (UnsupportedEncodingException ex) {
                        payloadSlimmed = "[unknown]";
                    }

                    trace.put("body", payloadSlimmed);
                }
            }
        } catch (IOException ioex) {
            trace.put("body", "EXCEPTION: " + ioex.getMessage());
        }
    }

    private void logTrace(HttpServletRequest request, Map<String, Object> trace) {
        Object method = trace.get("method");
        Object path = trace.get("path");
        Object statusCode = trace.get("statusCode");

        logger.info(String.format("%s %s produced an status code '%s'. Trace: '%s'", method, path, statusCode,
                trace));
    }

    protected Map<String, Object> getTrace(HttpServletRequest request, int status) {
        Throwable exception = (Throwable) request.getAttribute("javax.servlet.error.exception");

        Principal principal = request.getUserPrincipal();

        Map<String, Object> trace = new LinkedHashMap<String, Object>();
        trace.put("method", request.getMethod());
        trace.put("path", request.getRequestURI());
        if (null != principal) {
            trace.put("principal", principal.getName());
        }
        trace.put("query", request.getQueryString());
        trace.put("statusCode", status);

        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            String value = request.getHeader(key);
            trace.put("header:" + key, value);
        }

        if (exception != null && this.errorAttributes != null) {
            trace.put("error", this.errorAttributes
                    .getErrorAttributes((WebRequest) new ServletRequestAttributes(request), true));
        }

        return trace;
    }
}

Bitte nimm diesen Code mit einem Körnchen Salz.

Der wichtigste "Test" ist, wenn ein POST mit einer Nutzlast arbeitet. Dies ist, was "Double Read" -Probleme aufwirft.

pseudo-Beispielcode

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("myroute")
public class MyController {
    @RequestMapping(method = RequestMethod.POST, produces = "application/json")
    @ResponseBody
    public String getSomethingExample(@RequestBody MyCustomObject input) {

        String returnValue = "";

        return returnValue;
    }
}

Sie können "MyCustomObject" durch einfaches "Object" ersetzen, wenn Sie nur testen möchten.

Diese Antwort stammt aus mehreren verschiedenen SOF-Posts und Beispielen. Es hat jedoch eine Weile gedauert, bis alle zusammengekommen sind. Ich hoffe, es hilft einem zukünftigen Leser.

Bitte stimmen Sie Lathys Antwort vor meiner ab. Ohne sie wäre ich nicht so weit gekommen.

Unten ist eine/einige der Ausnahmen aufgeführt, die ich bei der Ausarbeitung dieses Problems hatte.

getReader () wurde bereits für diese Anfrage aufgerufen

Es sieht so aus, als wären einige der Orte, an denen ich "geliehen" habe, hier:

http://slackspace.de/articles/log-request-body-with-spring-boot/

https://github.com/c0nscience/spring-web-logging/blob/master/src/main/Java/org/zalando/springframework/web/logging/LoggingFilter.Java

https://howtodoinjava.com/servlets/httpservletrequestwrapper-example-read-request-body/

https://www.oodlestechnologies.com/blogs/How-to-create-duplicate-object-of-httpServletRequest-object

https://github.com/c0nscience/spring-web-logging/blob/master/src/main/Java/org/zalando/springframework/web/logging/LoggingFilter.Java

2
granadaCoder

Spring hat dafür eine eingebaute Unterstützung mit einem AbstractRequestLoggingFilter:

@Bean
public Filter loggingFilter(){
    final AbstractRequestLoggingFilter filter = new AbstractRequestLoggingFilter() {
        @Override
        protected void beforeRequest(final HttpServletRequest request, final String message) {

        }

        @Override
        protected void afterRequest(final HttpServletRequest request, final String message) {

        }
    };

    filter.setIncludePayload(true);
    filter.setIncludeQueryString(false);
    filter.setMaxPayloadLength(1000000);

    return filter;
}

Leider können Sie die Nutzdaten immer noch nicht direkt von der Anforderung lesen, aber der Parameter String message enthält die Nutzdaten, sodass Sie sie wie folgt abrufen können:

String body = message.substring(message.indexOf("{"), message.lastIndexOf("]"));

2
Markoorn

Das Überschreiben von getInputStream() hat in meinem Fall nicht funktioniert. Meine Server-Implementierung scheint Parameter zu analysieren, ohne diese Methode aufzurufen. Ich habe keinen anderen Weg gefunden, aber auch alle vier getParameter * -Methoden neu implementiert. Hier ist der Code von getParameterMap (verwendet von Apache Http Client und Google Guava Library):

@Override
public Map<String, String[]> getParameterMap() {
    Iterable<NameValuePair> params = URLEncodedUtils.parse(getQueryString(), NullUtils.UTF8);

    try {
        String cts = getContentType();
        if (cts != null) {
            ContentType ct = ContentType.parse(cts);
            if (ct.getMimeType().equals(ContentType.APPLICATION_FORM_URLENCODED.getMimeType())) {
                List<NameValuePair> postParams = URLEncodedUtils.parse(IOUtils.toString(getReader()), NullUtils.UTF8);
                params = Iterables.concat(params, postParams);
            }
        }
    } catch (IOException e) {
        throw new IllegalStateException(e);
    }
    Map<String, String[]> result = toMap(params);
    return result;
}

public static Map<String, String[]> toMap(Iterable<NameValuePair> body) {
    Map<String, String[]> result = new LinkedHashMap<>();
    for (NameValuePair e : body) {
        String key = e.getName();
        String value = e.getValue();
        if (result.containsKey(key)) {
            String[] newValue = ObjectArrays.concat(result.get(key), value);
            result.remove(key);
            result.put(key, newValue);
        } else {
            result.put(key, new String[] {value});
        }
    }
    return result;
}
1
30thh

Schauen Sie sich Spring AbstractRequestLoggingFilter an (oder verwenden Sie es)

0
GKislin

Wenn Sie die Kontrolle über die Anforderung haben, können Sie den Inhaltstyp auf binary/octet-stream setzen. Auf diese Weise können Parameter abgefragt werden, ohne den Eingabestream zu verbrauchen.

Dies kann jedoch für einige Anwendungsserver spezifisch sein. Ich habe nur Tomcat getestet, Jetty scheint sich laut https://stackoverflow.com/a/11434646/9571 genauso zu verhalten.

0
Olivier.Roger