Почему входной поток 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)
Ответы
Ответ 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
У меня была эта проблема с сообщением. Я решил это, сначала прочитав входной поток и поместив его в кеш, прежде чем читать параметры. Кажется, это трюк