web-dev-qa-db-fra.com

La requête Servlet Http perd les paramètres de POST le corps après l'avoir lu une fois

J'essaie d'accéder à deux paramètres de requête http dans un Java Filtre de servlet, rien de nouveau ici, mais j'ai été surpris de constater que les paramètres ont déjà été consommés! De ce fait, il n'est pas disponible plus dans la chaîne de filtre.

Il semble que cela ne se produise que lorsque les paramètres entrent dans un corps de requête POST (un formulaire à soumettre, par exemple)).

Existe-t-il un moyen de lire les paramètres sans les consommer?

Jusqu'à présent, je n'ai trouvé que cette référence: Le filtre de servlet utilisant request.getParameter perd les données du formulaire .

Merci!

73
amuniz

Par ailleurs, une solution alternative à ce problème consiste à ne pas utiliser la chaîne de filtres mais à créer votre propre composant d'intercepteur, en utilisant peut-être des aspects pouvant fonctionner sur le corps de la requête analysée. Il sera également probablement plus efficace, car vous ne convertissez qu'une seule fois la demande InputStream dans votre propre objet de modèle.

Cependant, je pense toujours qu'il est raisonnable de vouloir lire le corps de la requête plusieurs fois, en particulier au fur et à mesure que la requête se déplace dans la chaîne de filtrage. J'utilise généralement des chaînes de filtres pour certaines opérations que je souhaite conserver au niveau de la couche HTTP, découplées des composants de service.

Comme suggéré par Will Hartung , j’ai atteint cet objectif en étendant HttpServletRequestWrapper, en consommant la requête InputStream et en mettant essentiellement en cache les octets.

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

Le corps de la requête peut maintenant être lu plusieurs fois en encapsulant la requête d'origine avant de la transmettre à travers la chaîne de filtrage:

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

Cette solution vous permettra également de lire le corps de la requête plusieurs fois via les méthodes getParameterXXX car l'appel sous-jacent est getInputStream(), qui lira bien sûr la requête en cache InputStream.

Modifier

Pour les versions plus récentes de l'interface ServletInputStream. Vous devez fournir la mise en œuvre de quelques méthodes supplémentaires comme isReady, setReadListener etc. Reportez-vous à question comme indiqué dans le commentaire ci-dessous.

89
pestrella

Je sais que je suis en retard, mais cette question était toujours d'actualité pour moi et cet article SO était l'un des grands succès de Google. Je vais de l'avant et publie ma solution dans l'espoir que quelqu'un d'autre pourrait économiser quelques heures.

Dans mon cas, j'avais besoin de consigner toutes les demandes et les réponses avec leurs corps. En utilisant Spring Framework, la réponse est en réalité assez simple, il suffit d'utiliser ContentCachingRequestWrapper et 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

Les réponses ci-dessus ont été très utiles, mais mon expérience m'a quand même posé quelques problèmes. Sur Tomcat 7 servlet 3.0, les méthodes getParamter et getParamterValues ​​devaient également être remplacées. La solution ici inclut à la fois les paramètres get-query et le post-body. Cela permet d'obtenir facilement une chaîne brute.

Comme les autres solutions, il utilise Apache commons-io et Googles Guava.

Dans cette solution, les méthodes getParameter * ne lèvent pas IOException, mais utilisent super.getInputStream () (pour obtenir le corps), ce qui peut renvoyer IOException. Je l'attrape et jette runtimeException. Ce n'est pas si gentil.

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

La seule façon pour vous serait de consommer tout le flux d'entrée vous-même dans le filtre, de prendre ce que vous voulez, puis de créer un nouveau InputStream pour le contenu que vous lisez et de le placer dans un ServletRequestWrapper (ou HttpServletRequestWrapper).

L'inconvénient est que vous devez analyser la charge utile vous-même, la norme ne vous permet pas d'accéder à cette fonctionnalité.

Addenda -

Comme je l'ai dit, vous devez examiner HttpServletRequestWrapper.

Dans un filtre, vous continuez en appelant FilterChain.doFilter (demande, réponse).

Pour les filtres triviaux, la demande et la réponse sont les mêmes que celles transmises au filtre. Cela ne doit pas être le cas. Vous pouvez les remplacer par vos propres demandes et/ou réponses.

HttpServletRequestWrapper est spécialement conçu pour faciliter cela. Vous transmettez la demande initiale et vous pouvez alors intercepter tous les appels. Vous créez votre propre sous-classe et remplacez la méthode getInputStream par l'une des vôtres. Vous ne pouvez pas modifier le flux d'entrée de la demande d'origine, vous avez donc ce wrapper et vous retournez votre propre flux d'entrée.

Le cas le plus simple consiste à consommer le flux d'entrée des demandes d'origine dans un tampon d'octets, à faire la magie souhaitée, puis à créer un nouveau ByteArrayInputStream à partir de ce tampon. C'est ce qui est retourné dans votre wrapper, qui est passé à la méthode FilterChain.doFilter.

Vous devrez sous-classer ServletInputStream et créer un autre wrapper pour votre ByteArrayInputStream, mais ce n'est pas grave non plus.

4
Will Hartung

Moi aussi j'ai eu le même problème et je crois que le code ci-dessous est plus simple et qu'il fonctionne pour moi,

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

dans le filtre Java classe,

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

S'il vous plaît laissez-moi savoir si vous avez des questions

3
Lathy

Il s’agit donc essentiellement de la réponse de Lathy MAIS mise à jour pour répondre aux nouvelles exigences de ServletInputStream.

À savoir (pour ServletInputStream), il faut implémenter:

public abstract boolean isFinished();

public abstract boolean isReady();

public abstract void setReadListener(ReadListener var1);

Ceci est l'objet édité de Lathy

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

et quelque part (??) j'ai trouvé ceci (qui est une classe de première classe qui traite des méthodes "extra".

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

En fin de compte, j'essayais simplement de consigner les demandes. Et les morceaux ci-dessus frankensteined ensemble m'ont aidé à créer le ci-dessous.

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

S'il vous plaît prendre ce code avec un grain de sel.

Le "test" le plus important est si un POST fonctionne avec une charge utile. C’est ce qui exposera les problèmes de "double lecture".

pseudo exemple de code

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

Vous pouvez remplacer "MyCustomObject" par "Object" si vous souhaitez simplement tester.

Cette réponse est frankensteined à partir de plusieurs posts et exemples SOF différents .. mais il a fallu un certain temps pour tout rassembler, donc j'espère que cela aidera un futur lecteur.

Merci de voter la réponse de Lathy avant la mienne. Je n'aurais pas pu aller aussi loin sans cela.

Vous trouverez ci-dessous une/quelques-unes des exceptions que j'ai eues lors de la préparation de cette question.

getReader () a déjà été appelé pour cette requête

On dirait que certains des endroits que j'ai "empruntés" sont ici:

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 a un support intégré pour cela avec un 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;
}

Malheureusement, vous ne pourrez toujours pas lire la charge directement de la demande, mais le paramètre de message String inclura la charge afin que vous puissiez le récupérer comme suit:

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

2
Markoorn

Le simple remplacement de getInputStream() ne fonctionnait pas dans mon cas. L'implémentation de mon serveur semble analyser les paramètres sans appeler cette méthode. Je n'ai pas trouvé d'autre moyen, mais réinstallez également les quatre méthodes getParameter *. Voici le code de getParameterMap (client Apache Http et bibliothèque Google Guava utilisés):

@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

Consultez (ou utilisez) Spring AbstractRequestLoggingFilter

0
GKislin

Si vous avez le contrôle de la demande, vous pouvez définir le type de contenu sur binary/octet-stream . Cela permet de rechercher des paramètres sans consommer le flux d'entrée.

Toutefois, cela peut être spécifique à certains serveurs d'applications. Je n’ai testé que Tomcat, Jetty semble se comporter de la même façon selon https://stackoverflow.com/a/11434646/9571 .

0
Olivier.Roger