Подтвердить что ты не робот

Почему входной поток HttpServletRequest пуст?

У меня есть этот код, где я читаю входные данные из потока ввода запроса и использую JacksonMapper для преобразования в POJO. Его работа в контейнере 7 с прикрытием.

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    try {
        RequestType requestType = mapper.readValue(req.getInputStream(), RequestType.class);
    } Catch(Exception ex) {
        ....
    }
}

Однако иногда под нагрузкой генерируется следующее исключение. Я проверил мой клиент, и я уверен, что он отправит действительную строку 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)
4b9b3361

Ответ 1

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


Обновление:, похоже, это значение GAE 1.5. См. Также

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

Ответ 2

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

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

Внутри сервлета Apache Catalina, который запускается Spring, класс 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;
}

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

У меня была эта проблема с сообщением. Я решил это, сначала прочитав входной поток и поместив его в кеш, прежде чем читать параметры. Кажется, это трюк