Получение полезной нагрузки запроса из запроса POST в сервлете Java

113

У меня есть библиотека javascript, которая отправляет запрос POST на мой сервлет Java, но в этом doPostметоде я не могу получить содержимое полезной нагрузки запроса. В Chrome Developer Tools весь контент находится в разделе Request Payload на вкладке заголовков, и контент там, и я знаю, что POST получает метод doPost, но он просто пустой.

HttpServletRequest Как я могу получить данные в полезных данных запроса для объекта?

Действие request.getParameter()или request.getAttributes() оба заканчиваются без данных

Фасих Аван
источник
вам нужно указать, какой параметр, например, если у вас есть ключевое слово в теле, используйте String keyword = request.getParameter ("keyword");
justMe
Было бы интересно увидеть, как код JavaScript отправляет запрос. Видимо, неправильно составляет параметры запроса.
BalusC
@Razh ну да, я знаю, я просто указывал, какие методы я пробовал. BalusC Я использую библиотеку resumable.js для обработки разделенных загрузок файлов
Фасих Аван
4
Если я не ошибаюсь, важно, чтобы вы НЕ использовали request.getParameter () до чтения из входного потока, иначе данные не будут доступны (уже прочитаны).
Jeach

Ответы:

110

Простой ответ:
используйте getReader (), чтобы прочитать тело запроса.

Подробнее:
Есть два метода чтения данных в теле:

  1. getReader()возвращает BufferedReader , который позволит вам прочитать тело запроса.

  2. getInputStream()возвращает ServletInputStream, если вам нужно прочитать двоичные данные.

Примечание из документации: «[Любой метод] может быть вызван для чтения тела, но не оба».

davidfrancis
источник
4
Нет проблем, это немного скрыто
Дэвидфрансис
25
Этот пост может быть полезен, если вы только что использовали его в фильтре, а потом обнаружили, что больше ничто не может прочитать тело снова! natch3z.blogspot.co.uk/2009/01/read-request-body-in-filter.html
JonnyRaa
Это действительно плохой ответ.
SgtPooki
1
@SgtPooki, мой добрый сэр, не стесняйтесь добавлять аргументы в пользу этого комментария!
Дэвидфрэнсис
@davidfrancis Я не пытаюсь судить вас лично здесь, но: вы не предоставили никакого контекста .. ни ссылки на документацию, ни примера. Ваш ответ на мой комментарий, похоже, потребовал больше усилий, чем сам ответ.
SgtPooki
68
String payloadRequest = getBody(request);

Используя этот метод

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;
}
Адриан Айяла Торрес
источник
6
Учтите, что request.getInputStream()кодировка символов запроса не соблюдается, как это request.getReader()делает. Итак, в этом примере используется системная кодировка по умолчанию.
Вадим
9
new BufferedReader(new InputStreamReader(request.getInputStream()))можно упростить до того, request.getReader()что он уже буферизован, а также сохраняет кодировку запроса.
Вадим
1
Я нашел это решение полезным, так как возникло исключение: javax.servlet.ServletException: java.lang.IllegalStateException: getInputStream() has already been called for this requestкогда я вызвал getReader () в результате того, что читатель уже был открыт.
Benjamin Slabbert
52

Вы можете использовать Buffer Reader из запроса на чтение

    // 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()
Физер Хан
источник
40

Потоки Java 8

String body = request.getReader().lines()
    .reduce("", (accumulator, actual) -> accumulator + actual);
bbviana
источник
Это интересно, но выглядит неэффективным с точки зрения конкатенации строк! В любом случае это можно улучшить?
Дэвидфрэнсис
11
String body = request.getReader (). Lines (). Collect (Collectors.joining ()); также может работать. Collectors.joining, по-видимому, использует StringBuilder под капотом.
Оливер Колл,
3
Я думаю, что он должен request.getReader (). Lines (). Collect (joining ("\ n")), чтобы сохранить новые строки.
Майкл Бёклинг
В java 8 поток будет обрабатываться параллельно, поэтому необходимо добавить последовательный метод, иначе он объединит неправильную часть данных - String body = request.getReader (). Lines (). Sequence (). Reduce (System.lineSeparator (), ( аккумулятор, актуальный) -> аккумулятор + актуальный)
Jatin Bodarya 01
2
Вы можете заменить его (accumulator, actual) -> accumulator + actualна String::concat.
shmosel
26

С Apache Commons IO вы можете сделать это одной строкой.

IOUtils.toString(request.getReader())
Диджи Адейемо
источник
12

Если содержимое тела является строкой в ​​Java 8, вы можете сделать:

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

Ллойд Рочестер
источник
5

Если вы можете отправить полезную нагрузку в формате JSON, это наиболее удобный способ прочитать ее:

Пример класса данных:

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

Пример полезной нагрузки (тело запроса):

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

Код для чтения полезной нагрузки в сервлете (требуется com.google.gson. *):

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

Вот и все. Красиво, легко и чисто. Не забудьте установить заголовок content-type в application / json.

Гарри Разработчик
источник
2

Используя Java 8, попробуйте использовать ресурсы:

    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);
        }
    }
Тимоти Хайдер
источник
1

Вам нужно только

request.getParameterMap ()

для получения POST и GET - параметров.

Метод возвращает Map<String,String[]>.

Вы можете прочитать параметры на карте по

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
источник
2
Внимание: параметры доступны только в том случае, если вы используете кодировку application/x-www-form-urlencoded; поскольку multipart/form-dataвам, очевидно, нужно получить доступ к части тела request.getReader()и проанализировать ее вручную.
twonkeys