2011-12-15 11 views
14

Tengo este código donde leo la entrada de un flujo de entrada de solicitud y uso un JacksonMapper para convertirlo en un POJO. Se ejecuta en un embarcadero 7 contenedor con soporte guice.¿Por qué HttpServletRequest inputstream está vacío?

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

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

Sin embargo, a veces bajo carga se produce la siguiente excepción. Revisé a mi cliente y estoy seguro de que está enviando una cadena json válida. ¿Qué está pasando mal? ¿Es el comportamiento esperado de Jetty 7 bajo carga?

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) 

Respuesta

12

Va a estar vacío si ya se ha consumido de antemano. Esto se realizará implícitamente cuando llame a getParameter(), getParameterValues(), getParameterMap(), getReader(), etc. en el HttpServletRequest. Asegúrese de no llamar a ninguno de esos métodos que, por sí mismos, necesitan recopilar información del cuerpo de la solicitud antes de llamar al getInputStream(). Si su servlet no está haciendo eso, entonces comience a verificar los filtros del servlet que están mapeados en el mismo patrón de URL.


Actualización: esto parece ser GAE 1,5 específico. Ver también

Me temo que no hay solución/solución hasta que te lo arreglen. Puede probar para verificar si está disponible dentro de un Filter y, de ser así, copiarlo y almacenarlo como atributo de solicitud. Pero este podría afectar el procesamiento posterior por algún servlet GAE.

+0

No hay nada en mi código que lo consuma, pero Guice podría estar haciendo algo bajo el capó. –

+0

Puede * intentar * usar 'getQueryString()' en su lugar, solo no estoy seguro de cómo actúa GAE en las cadenas de consulta "sintácticamente inválidas". – BalusC

+0

Es una solicitud posterior y estoy sacando los datos de allí. –

6

Tuve el problema de que mi solicitud InputStream siempre estaba vacía con Jetty 6.1.15, y descubrí que la causaba un encabezado "Content-Type" faltante o incorrecto.

Genero las solicitudes en otro programa Java con HttpUrlConnection. Cuando no establecí explícitamente el encabezado Content-Type, el InputStream devuelto por request.getInputStream() en el programa receptor siempre estaba vacío. Cuando configuré el tipo de contenido como "binary/octet-stream", el InputStream de la solicitud contenía los datos correctos.

El único método que se llama en el objeto de solicitud antes de getInputStream() es getContentLength().

0

Estaba usando mod_jk 1.2.39 que tenía un error que causaba este problema. Después de actualizar a 1.2.40, comenzó a funcionar.

10

Tuve un problema similar al ejecutar una aplicación Spring Boot. La aplicación My Spring Boot es un servlet simple Dispatcher que lee el cuerpo de la solicitud y lo procesa.

En mi caso, el cliente (curl) establece un encabezado de tipo de contenido application/x-www-form-urlencoded si la línea de comando curl utiliza -d {some-data} y no establece una cabecera de tipo de contenido específico a través de -Hcontent-type=some-other-media-type.

Dentro del motor de servlets Apache Catalina que se ejecuta la primavera de arranque, la clase Request hace la siguiente prueba en parseParameters()

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

Para otros valores, content-typeRequest vuelve aquí, hecho.

Sin embargo, si el tipo de contenido partidosapplication/x-www-form-urlencoded, Request sigue:

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

que se consumir el cuerpo. Entonces en mi caso, aunque mi servlet no hace nada más que llamar al request.getInputStream() e intentar con read() desde él, ya es demasiado tarde - el motor de ejecución Request ya lee la entrada y no la almacena en búfer ni la lee. La única solución es establecer un Content-Type diferente.

El culpable es OrderedHiddenHttpMethodFilter(HiddenHttpMethodFilter).doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) línea 70

que está buscando el parámetro "_method" consulta.

que era capaz de desactivar el filtro añadiendo

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

(que fue utilizado para resolver another problem)

+1

Este es un gran descubrimiento, o no, HttpServletRequest en el controlador de correos del controlador siempre devuelve vacío sin motivo. –

+0

Esto fue difícil, 2 horas tratando de descubrir por qué la entidad postal estaba vacía. ¡Muchas gracias! – emerino

0

que he tenido este problema con un poste. Lo resolví PRIMERO al leer el inputstream y ponerlo en un caché, antes de leer los parámetros. Eso pareció ser el truco

Cuestiones relacionadas