Почему входной поток HttpServletRequest пуст? - PullRequest
16 голосов
/ 15 декабря 2011

У меня есть этот код, где я читаю ввод из потока ввода запроса и использую JacksonMapper для преобразования в POJO.Он работает в контейнере с молнией 7 с опорой для ободка.Я проверил мой клиент, и я уверен, что он отправляет правильную строку JSON.Что не так?Ожидается ли поведение Jetty 7 под нагрузкой?

java.io.EOFException: No content to map to Object due to end of input
    at org.codehaus.jackson.map.ObjectMapper._initForReading(ObjectMapper.java:2433)
    at org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2385)
    at org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1637)
    at com.ea.wsop.user.LoginServlet.processRequest(LoginServlet.java:69)
    at com.ea.wsop.user.LoginServlet.doPost(LoginServlet.java:63)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$doPost$0(<generated>)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke(<generated>)
    at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.java:228)
    at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72)
    at com.ea.monitor.MethodExecutionTimer.invoke(MethodExecutionTimer.java:130)
    at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72)
    at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.java:52)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.doPost(<generated>)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$service$8(<generated>)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke(<generated>)
    at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.java:228)
    at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72)
    at com.ea.monitor.MethodExecutionTimer.invoke(MethodExecutionTimer.java:130)
    at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72)
    at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.java:52)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.service(<generated>)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.CGLIB$service$9(<generated>)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd$$FastClassByGuice$$c6f479ee.invoke(<generated>)
    at com.google.inject.internal.cglib.proxy.$MethodProxy.invokeSuper(MethodProxy.java:228)
    at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72)
    at com.ea.monitor.MethodExecutionTimer.invoke(MethodExecutionTimer.java:130)
    at com.google.inject.internal.InterceptorStackCallback$InterceptedMethodInvocation.proceed(InterceptorStackCallback.java:72)
    at com.google.inject.internal.InterceptorStackCallback.intercept(InterceptorStackCallback.java:52)
    at com.ea.wsop.user.LoginServlet$$EnhancerByGuice$$a91c2ebd.service(<generated>)
    at com.google.inject.servlet.ServletDefinition.doService(ServletDefinition.java:263)

Ответы [ 6 ]

14 голосов
/ 15 декабря 2015

У меня была похожая проблема при запуске приложения Spring Boot. Приложение Spring Boot - это простой Dispatcher сервлет, который читает тело запроса и обрабатывает его.

В моем случае клиент (curl) устанавливает заголовок типа контента application / x-www-form-urlencoded, если в командной строке curl используется -d {some-data} и не устанавливает специальный заголовок типа контента через -Hcontent-type=some-other-media-type.

Внутри механизма сервлетов Apache Catalina, который запускается Spring Boot, класс Request выполняет следующий тест в parseParameters()

        if (!("application/x-www-form-urlencoded".equals(contentType))) {
            success = true;
            return;
        }

Для других content-type значений, Request возвращается сюда, готово.

Однако, если тип контента соответствует application/x-www-form-urlencoded, Request продолжается:

    try {
       if (readPostBody(formData, len) != len) {           
            parameters.setParseFailedReason(FailReason.REQUEST_BODY_INCOMPLETE);
            return;
        }
    } catch (....)

, который будет поглощать тело . Так что в моем случае, даже если мой сервлет не делает ничего, кроме как вызвать request.getInputStream() и попытаться read() с него, уже слишком поздно - среда выполнения Request уже читает ввод и буферизировать или не читать его. Единственный обходной путь - установить другой Content-Type.

виновник OrderedHiddenHttpMethodFilter(HiddenHttpMethodFilter).doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) строка 70

, который ищет параметр запроса "_method".

Мне удалось отключить фильтр, добавив

@Bean
public FilterRegistrationBean registration(HiddenHttpMethodFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(filter);
    registration.setEnabled(false);
    return registration;
}

(который был использован для решения другой проблемы )

12 голосов
/ 15 декабря 2011

Будет пустым, если он уже употреблен заранее. Это будет сделано неявно, когда вы звоните getParameter(), getParameterValues(), getParameterMap(), getReader() и т. Д. На HttpServletRequest. Убедитесь, что вы не вызываете ни один из тех методов, которые сами по себе должны собрать информацию из тела запроса перед вызовом getInputStream(). Если ваш сервлет этого не делает, тогда начните проверять фильтры сервлета, которые сопоставлены с одним и тем же шаблоном URL.


Обновление: похоже, что это GAE 1.5 специфично. Смотри также

Боюсь, что нет решения / обходного пути, пока они не исправят это. Вы можете попробовать , чтобы проверить, доступен ли он внутри Filter, и если да, то скопируйте и сохраните его как атрибут запроса. Но это может повлиять на дальнейшую обработку некоторым сервлетом GAE.

6 голосов
/ 11 июля 2012

У меня была проблема с тем, что мой запрос InputStream всегда был пустым с Jetty 6.1.15, и обнаружил, что он был вызван отсутствующим или неправильным заголовком «Content-Type».

Я генерирую запросы вдругая программа на Java с HttpUrlConnection.Когда я не устанавливал заголовок Content-Type явно, InputStream, возвращаемый request.getInputStream() в принимающей программе, всегда был пустым.Когда я установил тип содержимого «двоичный / поток октетов», InputStream запроса содержал правильные данные.

Единственный метод, который вызывается для объекта запроса до getInputStream(), это getContentLength().

0 голосов
/ 03 сентября 2018

Системный подход:

  1. Получите исходный код для вашего контейнера или, по крайней мере, его веб-часть (может быть трудно найти), импортируйте в вашу IDE.
  2. Сделайте перерывукажите в своем коде, где раньше вызывается HttpServletRequest->getInputStream().
  3. Войдите в метод HttpServletRequest->getInputStream(), теперь вы в каком-то ... классе Impl.
  4. Установите новую точку останова в этой реализации getInputStream() или даже в ее методе read().
  5. Повторите тестовый вызов и посмотрите, что потребляет ваши данные.
0 голосов
/ 27 апреля 2017

У меня была эта проблема с постом. Я решил это ПЕРВЫМ чтением входного потока и помещением его в кеш, перед чтением параметров. Это, казалось, сделало трюк

0 голосов
/ 21 апреля 2014

Я использовал mod_jk 1.2.39 с ошибкой, вызвавшей эту проблему. После обновления до 1.2.40 заработало.

...