Pobieranie ładunku żądania z żądania POST w serwlecie Java

113

Mam bibliotekę javascript, która wysyła żądanie POST do mojego serwletu Java, ale w doPostmetodzie nie mogę uzyskać zawartości ładunku żądania. W chrome Developer Tools, cała zawartość znajduje się w sekcji Request Payload na karcie nagłówków, i tam jest, i wiem, że POST jest odbierany metodą doPost, ale po prostu jest pusty.

Dla HttpServletRequest obiektu, w jaki sposób mogę uzyskać dane w ładunku żądania?

Wykonanie request.getParameter()lub request.getAttributes() jedno i drugie kończy się bez danych

Fasih Awan
źródło
musisz określić, który parametr, np. jeśli masz słowo kluczowe w treści użyj String keyword = request.getParameter ("keyword");
justMe
Byłoby interesujące zobaczyć, jak kod JavaScript wysyła żądanie. Najwyraźniej tworzy parametry żądania w niewłaściwy sposób.
BalusC,
@Razh cóż, tak, wiem, właśnie określałem, które metody próbowałem. BalusC Używam biblioteki resumable.js do obsługi przesyłania podzielonych plików
Fasih Awan
4
Jeśli się nie mylę, ważne jest, aby NIE używać request.getParameter () przed odczytem ze strumienia wejściowego, w przeciwnym razie żadne dane nie będą dostępne (już odczytane).
Jeach

Odpowiedzi:

110

Prosta odpowiedź:
użyj metody getReader (), aby odczytać treść żądania

Więcej informacji:
istnieją dwie metody odczytu danych w treści:

  1. getReader()zwraca BufferedReader , który umożliwi odczytanie treści żądania.

  2. getInputStream()zwraca ServletInputStream, jeśli chcesz odczytać dane binarne.

Uwaga z dokumentacji: „[Każda metoda] może zostać wywołana w celu odczytania treści, a nie obu”.

davidfrancis
źródło
4
Żaden problem, to trochę ukryte
davidfrancis
25
Ten post może być przydatny, jeśli właśnie użyłeś tego w filtrze, a potem odkryłeś, że nic innego nie może ponownie odczytać treści! natch3z.blogspot.co.uk/2009/01/read-request-body-in-filter.html
JonnyRaa
To naprawdę zła odpowiedź.
SgtPooki
1
@SgtPooki zapraszam do dodania uzasadnienia dla tego komentarza, mój dobry panie!
davidfrancis
@davidfrancis Nie próbuję cię tu oceniać osobiście, ale: nie podałeś żadnego kontekstu… żadnego linku do dokumentacji, żadnego przykładu. Twoja odpowiedź na mój komentarz wymagała więcej wysiłku niż sama odpowiedź.
SgtPooki
68
String payloadRequest = getBody(request);

Korzystając z tej metody

public static String getBody(HttpServletRequest request) throws IOException {

    String body = null;
    StringBuilder stringBuilder = new StringBuilder();
    BufferedReader bufferedReader = null;

    try {
        InputStream inputStream = request.getInputStream();
        if (inputStream != null) {
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            char[] charBuffer = new char[128];
            int bytesRead = -1;
            while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                stringBuilder.append(charBuffer, 0, bytesRead);
            }
        } else {
            stringBuilder.append("");
        }
    } catch (IOException ex) {
        throw ex;
    } finally {
        if (bufferedReader != null) {
            try {
                bufferedReader.close();
            } catch (IOException ex) {
                throw ex;
            }
        }
    }

    body = stringBuilder.toString();
    return body;
}
Adrian Ayala Torres
źródło
6
Weź pod uwagę, że request.getInputStream()nie honoruje to tak jak kodowanie znaków żądania request.getReader(). Więc w tym przykładzie zastosowano domyślny systemowy zestaw znaków.
Vadzim
9
new BufferedReader(new InputStreamReader(request.getInputStream()))można uprościć do request.getReader()tego, że jest już buforowany, a także zachowuje kodowanie żądań.
Vadzim
1
To rozwiązanie okazało się pomocne, ponieważ został wyrzucony wyjątek: javax.servlet.ServletException: java.lang.IllegalStateException: getInputStream() has already been called for this requestkiedy wywołałem getReader () w wyniku otwarcia czytnika.
Benjamin Slabbert
52

Możesz używać czytnika buforów od żądania do odczytu

    // Read from request
    StringBuilder buffer = new StringBuilder();
    BufferedReader reader = request.getReader();
    String line;
    while ((line = reader.readLine()) != null) {
        buffer.append(line);
    }
    String data = buffer.toString()
Fizer Khan
źródło
40

Strumienie Java 8

String body = request.getReader().lines()
    .reduce("", (accumulator, actual) -> accumulator + actual);
bbviana
źródło
Jest to interesujące, ale wygląda na dość nieefektywne pod względem konkatenacji ciągów! Czy można to poprawić?
davidfrancis
11
String body = request.getReader (). Lines (). Collect (Collectors.joining ()); może również działać. Collectors.joining najwyraźniej używa StringBuildera pod maską.
Oliver Kohll
3
Myślę, że powinno request.getReader (). Lines (). Collect (join (łączenie ("\ n"))), aby zachować nowe linie.
Michael Böckling
W java 8 strumień będzie przetwarzany równolegle, więc należy dodać metodę sekwencyjną, w przeciwnym razie połączy on niewłaściwą część danych - String body = request.getReader (). Lines (). Sequential (). Redukuj (System.lineSeparator (), ( akumulator, rzeczywisty) -> akumulator + rzeczywisty)
Jatin Bodarya
2
Można wymienić (accumulator, actual) -> accumulator + actualz String::concat.
shmosel
12

Jeśli zawartość ciała jest ciągiem w Javie 8, możesz zrobić:

String body = request.getReader().lines().collect(Collectors.joining());

Lloyd Rochester
źródło
5

Jeśli możesz wysłać ładunek w formacie JSON, jest to najwygodniejszy sposób na odczytanie listy odtwarzania:

Przykładowa klasa danych:

public class Person {
    String firstName;
    String lastName;
    // Getters and setters ...
}

Przykładowy ładunek (treść żądania):

{ "firstName" : "John", "lastName" : "Doe" }

Kod do odczytu ładunku w serwlecie (wymaga com.google.gson. *):

Person person = new Gson().fromJson(request.getReader(), Person.class);

To wszystko. Ładny, łatwy i czysty. Nie zapomnij ustawić nagłówka typu zawartości na application / json.

Harry Developer
źródło
2

Użyj Java 8 spróbuj z zasobami:

    StringBuilder stringBuilder = new StringBuilder();
    try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream()))) {
        char[] charBuffer = new char[1024];
        int bytesRead;
        while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
            stringBuilder.append(charBuffer, 0, bytesRead);
        }
    }
Timothy Heider
źródło
1

Potrzebujesz tylko

request.getParameterMap ()

aby uzyskać POST i GET - Parametry.

Metoda zwraca plik Map<String,String[]>.

Możesz odczytać parametry w Mapie wg

Map<String, String[]> map = request.getParameterMap();
//Reading the Map
//Works for GET && POST Method
for(String paramName:map.keySet()) {
    String[] paramValues = map.get(paramName);

    //Get Values of Param Name
    for(String valueOfParam:paramValues) {
        //Output the Values
        System.out.println("Value of Param with Name "+paramName+": "+valueOfParam);
    }
}
Arol
źródło
2
Uwaga: parametry są dostępne tylko wtedy, gdy używasz kodowania application/x-www-form-urlencoded; ponieważ multipart/form-datanajwyraźniej musisz uzyskać dostęp do części ciała request.getReader()i przeanalizować ją ręcznie.
twonkeys