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

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

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

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


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

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


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

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.


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

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

1
Was ist PortalUtil?
Fähre Kranenburg

Ich wette, dies ist von Liferay, Liferay-spezifische API
mvmn
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.