Ottieni il corpo della richiesta POST da HttpServletRequest


115

Sto cercando di ottenere l'intero corpo dall'oggetto HttpServletRequest.

Il codice che sto seguendo è simile a questo:

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

e sto testando la funzionalità con curl e wget come segue:

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"

Ma while ( (bytesRead = bufferedReader.read(charBuffer)) != -1 )non restituisce nulla, quindi non ottengo nulla aggiunto a StringBuffer.

Risposte:


192

In Java 8, puoi farlo in un modo più semplice e pulito:

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

8
Preferisco questa soluzione perché è un Java puro senza alcuna dipendenza da terze parti.
lu_ko

49
Tuttavia, tieni presente che non possiamo leggere nuovamente il corpo della richiesta poiché getReaderè già stato chiamato.
Nikhil Sahu

1
Come possiamo reimpostare nuovamente i dati POST HTTP appena formattati nella richiesta?
Pra_A

1
Ho provato questa soluzione ma ha introdotto un preblem molto serio, ho usato questo codice per registrare le informazioni sulla richiesta all'interno di un filtro oncePerRequest e quando l'ho usato, tutto il mio binding @modelAttribute in tutti i miei metodi di post ha dato null in tutti i campi di un oggetto Non consiglio di utilizzare questo approccio.
Mohammed Fathi,

Non dovremmo chiudere il lettore?
aristo_sh

46

Modo semplice con commons-io.

IOUtils.toString(request.getReader());

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


Ti aiuterei se potessi fornire un esempio di come apparirebbe l'output del lettore (ad esempio mostra le chiavi o meno)
ArthurG

Questo ha funzionato per me. Posso confermare che questa soluzione evita anche uno scenario comune in cui bufferedreader.readLine () "si blocca" senza una ragione apparente
Naren

Ciao @DavidDomingo, funziona al 100%, posso leggere che stai commentando lo stesso nella risposta sopra questa (che funziona anche tu). Controlla che da qualche parte nel tuo codice (filtri probabilmente), o forse perché qualcuno di Spring, il metodo getReader () non è stato chiamato prima, perché se lo chiami due o più volte, restituisce solo il primo payload.
Dani il

Ciao @Dani, ecco perché non funziona. Il lettore è vuoto. Penso che il RestController lo legga prima che tu sia in grado di farlo in qualsiasi endpoint. Il modo più semplice per ottenere il corpo è usare HttpEntity.
David Domingo

31

Tieni presente che il tuo codice è piuttosto rumoroso. So che il thread è vecchio, ma molte persone lo leggeranno comunque. Puoi fare la stessa cosa usando la libreria guava con:

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

3
Forse consideraif(RequestMethod.POST.name().equalsIgnoreCase(...)) { ... }
Madbreaks

Ottengo java.lang.IllegalStateException: getReader () è già stato chiamato per questa richiesta
Pra_A

18

Se tutto ciò che vuoi è il corpo della richiesta POST, puoi usare un metodo come questo:

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

Credito a: https://stackoverflow.com/a/5445161/1389219


1
Tieni presente che request.getInputStream()non rispetta la codifica dei caratteri della richiesta come request.getReader()fa. +1 per il collegamento però.
Vadzim

quale dovrebbe essere l'equivalente per il metodo PUT?
devanathan

10

Funziona sia per GET che per 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

Se il corpo della richiesta è vuoto, significa semplicemente che è già stato consumato in anticipo. Ad esempio, da a request.getParameter(), getParameterValues()o getParameterMap()call. Rimuovi semplicemente le linee che effettuano quelle chiamate dal tuo codice.


Funziona solo se non si tratta di un caricamento di file, come curlnell'esempio, no?
Dave Newton

1
Ho provato questa cosa. Ma ancora non ricevo il corpo POST. Devo essermi perso qualcosa. Solo per aggiungere: sto usando Tapestry per lo sviluppo.
patel bhavin

3

Funzionerà con tutti i metodi 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

Ho risolto quella situazione in questo modo. Ho creato un metodo util che restituisce un oggetto estratto dal corpo della richiesta, utilizzando il metodo readValue di ObjectMapper che è in grado di ricevere 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
cos'è PortalUtil?
Traghetto Kranenburg

Scommetto che proviene da Liferay, API specifica di Liferay
mvmn
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.