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 "[email protected] 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.

Patel Bhavin
la source

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

Dani
la source
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());
    }
afx
la source
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

vegemite4me
la source
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 "";
}
Bruno Lee
la source
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.

BalusC
la source
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;
    }
}
Bhawna Joshi
la source
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;
}
Francisco Disalvo
la source
1
qu'est-ce que PortalUtil?
Ferry Kranenburg le
Je parie que cela vient de Liferay, API spécifique à Liferay
mvmn