В качестве тела HttpServletRequest всегда возвращает CoyoteInputStream, а не фактическое тело

Я пытаюсь написать метод, который проверяет учетные данные пользователя, и если это правильный синтаксический анализ, отправленный JSON. Он работает нормально, но я не могу получить доступ к JSON. В моем коде есть команда InputStream inputStream = request.getInputStream();, которая должна читать JSON, но каждый раз возвращает org.apache.catalina.connector.CoyoteInputStream@3f1e9348. Взгляните на мой код:

@POST
@Path("auth")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_HTML)
public String controller(@Context HttpServletRequest request) {


    String authorization = request.getHeader("Authorization");
    if (authorization == null) {
        authorization = request.getHeader("authorization");
    }

    String basicHeader = "basic";
    if (authorization != null && authorization.toLowerCase().startsWith(basicHeader)) {
        String base64Credentials = authorization.substring(basicHeader.length()).trim();
        String credentials = new String(Base64.getDecoder().decode(base64Credentials),
                Charset.forName("UTF-8"));
        String[] values = credentials.split(":", 2);
    }

    try {
        InputStream inputStream = request.getInputStream();
        System.out.println(inputStream);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Когда я пытаюсь использовать request.getReader(), я получаю печально известное исключение IllegalStateException: getInputStream() has already been called for this request. См. Соответствующий фрагмент кода:

if ("POST".equalsIgnoreCase(request.getMethod()))
        {
            try {
                String req = request.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

Я использую curl для отправки POST:

curl -u myusername:mypasswor -H "Content-Type: application/json"
-X POST -d '{"username":"xyz","password":"xyz"}' localhost
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
533
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете получить содержимое тела, объявив параметр в своем методе:

public String controller(String body, @Context HttpServletRequest request) 

Но вы также можете получить реализацию JAX-RS для десериализации этого JSON до вашего предполагаемого типа:

public String controller(MyExpectedType body, @Context HttpServletRequest request) 

Это должно сработать, потому что вы объявили ожидаемый тип контента, если у вас есть подходящий поставщик (например, jackson-jaxrs ...).

Что касается ошибки входного потока: это, вероятно, связано с тем, что реализация JAXRS контейнера уже проанализировала запрос.

Но если бы вы обрабатывали его в обычном сценарии, например, в сервлете, вам все равно пришлось бы исправить то, как вы его читаете:

В документации для getInputStream указано:

Retrieves the body of the request as binary data using a ServletInputStream. Either this method or getReader() may be called to read the body, not both.

Это означает, что чтобы получить контент, отправленный вашим клиентом, в теле, вам нужно прочитать поток:

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

Вы также можете использовать API на основе Stream:

byte[] bytes = new byte[request.getContentLength()];
request.getInputStream().read(bytes);
String body = new String(bytes); //you may need to specify the character set

Фактический класс входного потока основан на реализации (предоставляется контейнером), поэтому вам не нужно беспокоиться о CoyoteInputStream.

Как я уже сказал, получается java.lang.IllegalStateException: getInputStream() has already been called for this request.

menteith 22.03.2018 10:54

Мой комментарий относился к вашему первому решению. Однако в вашем отредактированном ответе метод Stream-based API: работает нормально.

menteith 22.03.2018 10:59

Отредактированный ответ :-)

ernest_k 22.03.2018 11:01

Спасибо! MyExpectedType body - это та часть, которая мне понравилась, так как таким образом я получаю свой JSON.

menteith 22.03.2018 11:23

Другие вопросы по теме