Rufen Sie den POST-Anforderungshauptteil von HttpServletRequest ab

113

Ich versuche, den gesamten Körper aus dem HttpServletRequest-Objekt abzurufen.

Der Code, dem ich folge, sieht folgendermaßen aus:

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

und ich teste die Funktionalität mit Curl und Wget wie folgt:

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"

Aber das while ( (bytesRead = bufferedReader.read(charBuffer)) != -1 )gibt nichts zurück und so bekomme ich nichts an StringBuffer angehängt.

Patel Bhavin
quelle

Antworten:

190

In Java 8 können Sie dies einfacher und sauberer tun:

if ("POST".equalsIgnoreCase(request.getMethod())) 
{
   test = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
}
abhi
quelle
7
Ich bevorzuge diese Lösung, da es sich um reines Java ohne Abhängigkeit von Drittanbietern handelt.
lu_ko
49
Beachten Sie jedoch, dass wir den getReaderbereits aufgerufenen Anfragetext nicht erneut lesen können .
Nikhil Sahu
1
Wie können wir die neu formatierten HTTP-POST-Daten wieder in die Anfrage zurücksetzen?
Pra_A
1
Ich habe diese Lösung ausprobiert, aber sie führte zu einem sehr schwerwiegenden Problem. Ich habe diesen Code verwendet, um Anforderungsinformationen in einem OncePerRequest-Filter zu protokollieren. Als ich sie verwendete, ergab meine gesamte @ modelAttribute-Bindung in allen meinen Post-Methoden in allen Feldern von null Objekt. Ich empfehle nicht, diesen Ansatz zu verwenden.
Mohammed Fathi
Sollten wir den Leser nicht schließen?
aristo_sh
46

Einfacher Weg mit Commons-Io.

IOUtils.toString(request.getReader());

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

Dani
quelle
Ich würde helfen, wenn Sie ein Beispiel dafür geben könnten, wie die Ausgabe des Lesers aussehen würde (dh Schlüssel
anzeigen
Das hat bei mir funktioniert. Ich kann bestätigen, dass diese Lösung auch ein häufiges Szenario vermeidet, in dem bufferedreader.readLine () ohne ersichtlichen Grund "hängt"
Naren
Hallo @DavidDomingo, es funktioniert 100%, ich kann lesen, dass Sie das gleiche in der Antwort über dieser kommentieren (was auch funktioniert). Überprüfen Sie, ob irgendwo in Ihrem Code (wahrscheinlich Filter) oder weil jemand von Spring die Methode getReader () vorher nicht aufgerufen wurde, denn wenn Sie sie zweimal oder mehrmals aufrufen, wird nur die erste Nutzlast zurückgegeben.
Dani
Hallo @Dani, deshalb funktioniert es nicht. Der Leser ist leer. Ich denke, dass der RestController es liest, bevor Sie es in einem Endpunkt tun können. Der einfachste Weg, um den Körper zu bekommen, ist die Verwendung von HttpEntity.
David Domingo
31

Beachten Sie, dass Ihr Code ziemlich laut ist. Ich weiß, dass der Thread alt ist, aber viele Leute werden ihn trotzdem lesen. Mit der Guavenbibliothek können Sie dasselbe tun mit:

    if ("POST".equalsIgnoreCase(request.getMethod())) {
        test = CharStreams.toString(request.getReader());
    }
afx
quelle
3
Vielleicht überlegenif(RequestMethod.POST.name().equalsIgnoreCase(...)) { ... }
Madbreaks
Ich erhalte die java.lang.IllegalStateException: getReader () wurde bereits für diese Anfrage
aufgerufen
18

Wenn Sie nur den POST-Anforderungshauptteil möchten, können Sie eine Methode wie die folgende verwenden:

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

Gutschrift an: https://stackoverflow.com/a/5445161/1389219

vegemite4me
quelle
1
Berücksichtigen Sie, dass request.getInputStream()die Codierung von Anforderungszeichen nicht berücksichtigt request.getReader()wird. +1 für den Link.
Vadzim
Was sollte das Äquivalent für die PUT-Methode sein?
Devanathan
10

Dies funktioniert sowohl für GET als auch für 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
quelle
9

Wenn der Anforderungshauptteil leer ist, bedeutet dies einfach, dass er bereits zuvor verbraucht wurde. Zum Beispiel von einem request.getParameter(), getParameterValues()oder getParameterMap()Anruf. Entfernen Sie einfach die Leitungen, die diese Anrufe tätigen, aus Ihrem Code.

BalusC
quelle
Das funktioniert nur, wenn es sich nicht um einen Datei-Upload handelt, wie im curlBeispiel, nein?
Dave Newton
1
Ich habe es versucht. Aber ich bekomme immer noch nicht den POST-Körper. Mir muss etwas fehlen. Nur um es hinzuzufügen: Ich verwende Tapisserie für die Entwicklung.
Patel Bhavin
3

Dies funktioniert für alle HTTP-Methoden.

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
quelle
0

Ich habe diese Situation auf diese Weise gelöst. Ich habe eine util-Methode erstellt, die ein aus dem Anforderungshauptteil extrahiertes Objekt zurückgibt. Dabei habe ich die readValue-Methode von ObjectMapper verwendet, die einen Reader empfangen kann.

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
quelle
1
Was ist PortalUtil?
Fähre Kranenburg
Ich wette, dies ist von Liferay, Liferay-spezifische API
mvmn