Obtenez le corps de la requête POST à ​​partir de HttpServletRequest


115

J'essaye d'obtenir le corps entier de l'objet HttpServletRequest.

Le code que je suis ressemble à ceci:

if ( request.getMethod().equals("POST") )
{
    StringBuffer sb = new StringBuffer();
    BufferedReader bufferedReader = null;
    String content = "";

    try {
        //InputStream inputStream = request.getInputStream();
        //inputStream.available();
        //if (inputStream != null) {
        bufferedReader =  request.getReader() ; //new BufferedReader(new InputStreamReader(inputStream));
        char[] charBuffer = new char[128];
        int bytesRead;
        while ( (bytesRead = bufferedReader.read(charBuffer)) != -1 ) {
            sb.append(charBuffer, 0, bytesRead);
        }
        //} else {
        //        sb.append("");
        //}

    } catch (IOException ex) {
        throw ex;
    } finally {
        if (bufferedReader != null) {
            try {
                bufferedReader.close();
            } catch (IOException ex) {
                throw ex;
            }
        }
    }

    test = sb.toString();
}

et je teste la fonctionnalité avec curl et wget comme suit:

curl --header "MD5: abcd" -F "fileupload=@filename.txt http://localhost:8080/abcd.html"

wget --header="MD5: abcd" --post-data='{"imei":"351553012623446","hni":"310150","wdp":false}' http://localhost:8080/abcd.html"

Mais le while ( (bytesRead = bufferedReader.read(charBuffer)) != -1 )ne renvoie rien, donc je n'ai rien ajouté sur StringBuffer.

Réponses:


192

Dans Java 8, vous pouvez le faire de manière plus simple et propre:

if ("POST".equalsIgnoreCase(request.getMethod())) 
{
   test = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
}

8
Je préfère cette solution car c'est un pur Java sans aucune dépendance tierce.
lu_ko

49
Cependant, gardez à l'esprit que nous ne pouvons pas relire le corps de la requête comme cela getReadera déjà été appelé.
Nikhil Sahu

1
Comment pouvons-nous à nouveau remettre en requête les données HTTP POST nouvellement formatées?
Pra_A

1
J'ai essayé cette solution mais elle a introduit un pré-problème très sérieux, j'ai utilisé ce code pour consigner les informations de demande dans un filtre oncePerRequest, et quand je l'ai utilisé, toutes mes liaisons @modelAttribute dans toutes mes méthodes de publication ont donné null dans tous les champs d'un objet .Je ne recommande pas d'utiliser cette approche.
Mohammed Fathi le

Ne devrions-nous pas fermer le lecteur?
aristo_sh

46

Un moyen simple avec commons-io.

IOUtils.toString(request.getReader());

https://commons.apache.org/proper/commons-io/javadocs/api-2.5/org/apache/commons/io/IOUtils.html


Je vous aiderais si vous pouviez donner un exemple de l'apparence de la sortie du lecteur (c'est-à-dire afficher les clés ou non)
ArthurG

Cela a fonctionné pour moi. Je peux confirmer que cette solution évite également un scénario courant où bufferedreader.readLine () "se bloque" sans raison apparente
Naren

Salut @DavidDomingo, cela fonctionne à 100%, je peux lire que vous commentez la même chose dans la réponse ci-dessus (qui fonctionne également). Vérifiez que quelque part dans votre code (filtre probablement), ou peut-être parce que quelqu'un de Spring, la méthode getReader () n'est pas appelée auparavant, car si vous l'appelez deux fois ou plus, elle ne renvoie la charge utile que la première.
Dani

Salut @Dani, c'est pourquoi ça ne marche pas. Le lecteur est vide. Je pense que le RestController le lit avant que vous ne puissiez le faire dans n'importe quel point final. Le moyen le plus simple d'obtenir le corps est d'utiliser HttpEntity.
David Domingo

31

Sachez que votre code est assez bruyant. Je sais que le fil est vieux, mais beaucoup de gens le liront de toute façon. Vous pouvez faire la même chose en utilisant la bibliothèque goyave avec:

    if ("POST".equalsIgnoreCase(request.getMethod())) {
        test = CharStreams.toString(request.getReader());
    }

3
Peut-être envisagerif(RequestMethod.POST.name().equalsIgnoreCase(...)) { ... }
Madbreaks

J'obtiens l'exception java.lang.IllegalStateException: getReader () a déjà été appelé pour cette requête
Pra_A

18

Si tout ce que vous voulez est le corps de la requête POST, vous pouvez utiliser une méthode comme celle-ci:

static String extractPostRequestBody(HttpServletRequest request) throws IOException {
    if ("POST".equalsIgnoreCase(request.getMethod())) {
        Scanner s = new Scanner(request.getInputStream(), "UTF-8").useDelimiter("\\A");
        return s.hasNext() ? s.next() : "";
    }
    return "";
}

Crédit à: https://stackoverflow.com/a/5445161/1389219


1
Tenez compte du fait que request.getInputStream()cela n'honore pas le codage des caractères de la demande comme le request.getReader()fait. +1 pour le lien cependant.
Vadzim

quel devrait être l'équivalent de la méthode PUT?
devanathan

10

Cela fonctionne pour GET et POST:

@Context
private HttpServletRequest httpRequest;


private void printRequest(HttpServletRequest httpRequest) {
    System.out.println(" \n\n Headers");

    Enumeration headerNames = httpRequest.getHeaderNames();
    while(headerNames.hasMoreElements()) {
        String headerName = (String)headerNames.nextElement();
        System.out.println(headerName + " = " + httpRequest.getHeader(headerName));
    }

    System.out.println("\n\nParameters");

    Enumeration params = httpRequest.getParameterNames();
    while(params.hasMoreElements()){
        String paramName = (String)params.nextElement();
        System.out.println(paramName + " = " + httpRequest.getParameter(paramName));
    }

    System.out.println("\n\n Row data");
    System.out.println(extractPostRequestBody(httpRequest));
}

static String extractPostRequestBody(HttpServletRequest request) {
    if ("POST".equalsIgnoreCase(request.getMethod())) {
        Scanner s = null;
        try {
            s = new Scanner(request.getInputStream(), "UTF-8").useDelimiter("\\A");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return s.hasNext() ? s.next() : "";
    }
    return "";
}

9

Si le corps de la requête est vide, cela signifie simplement qu'il a déjà été consommé au préalable. Par exemple, par un request.getParameter(), getParameterValues()ou un getParameterMap()appel. Supprimez simplement les lignes effectuant ces appels de votre code.


Cela ne fonctionne que si ce n'est pas un téléchargement de fichier, comme dans l' curlexemple, non?
Dave Newton

1
J'ai essayé cette chose. Mais je ne reçois toujours pas le corps POST. J'ai dû louper quelque chose. Juste pour ajouter: j'utilise Tapestry pour le développement.
patel bhavin

3

Cela fonctionnera pour toutes les méthodes HTTP.

public class HttpRequestWrapper extends HttpServletRequestWrapper {
    private final String body;

    public HttpRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        body = IOUtils.toString(request.getReader());
    }

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

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener listener) {
            }

        };
        return servletInputStream;
    }

    public String getBody() {
        return this.body;
    }
}

0

J'ai résolu cette situation de cette manière. J'ai créé une méthode util qui renvoie un objet extrait du corps de la requête, en utilisant la méthode readValue d'ObjectMapper capable de recevoir un Reader.

public static <T> T getBody(ResourceRequest request, Class<T> class) {
    T objectFromBody = null;
    try {
        ObjectMapper objectMapper = new ObjectMapper();
        HttpServletRequest httpServletRequest = PortalUtil.getHttpServletRequest(request);
        objectFromBody = objectMapper.readValue(httpServletRequest.getReader(), class);
    } catch (IOException ex) {
        log.error("Error message", ex);
    }
    return objectFromBody;
}

1
qu'est-ce que PortalUtil?
Ferry Kranenburg le

Je parie que cela vient de Liferay, API spécifique à Liferay
mvmn
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.