2011-02-17 11 views
51

Estoy tratando de obtener los datos de la publicación en Java. Parece que debería ser una de las cosas más simples de hacer, ¿verdad? Quiero decir, HttpServletRequest.getParameter tiene que hacerlo ¿verdad? Entonces, ¿cómo puedes obtener los datos de publicación sin procesar?Cómo recuperar datos de entrada sin formato de HttpServletRequest en java

Encontré HttpServletRequest get JSON POST data y utilicé el código de Kdeveloper para extraer los datos de la publicación de una solicitud. Funciona, pero hay una trampa: solo puedo obtener los datos de la publicación una vez.

Aquí está el método que hice de código de Kdeveloper:

public static String getPostData(HttpServletRequest req) { 
    StringBuilder sb = new StringBuilder(); 
    try { 
     BufferedReader reader = req.getReader(); 
     reader.mark(10000); 

     String line; 
     do { 
      line = reader.readLine(); 
      sb.append(line).append("\n"); 
     } while (line != null); 
     reader.reset(); 
     // do NOT close the reader here, or you won't be able to get the post data twice 
    } catch(IOException e) { 
     logger.warn("getPostData couldn't.. get the post data", e); // This has happened if the request's reader is closed  
    } 

    return sb.toString(); 
} 

Anteriormente ya habían cerrado el lector al final de este método, pero la causada excepciones cuando el método corrió más de una vez en la misma petición. Sin cerrarlo, no se producen excepciones, pero el método devuelve una cadena vacía.

Honestamente, debería haber solo un método req.getPostData() expuesto - ¿nadie pensó que sería útil?

Entonces, ¿cómo puedo escribir este método para que siempre devuelva los datos de publicación correctos?

Respuesta

81

El cuerpo de la solicitud está disponible en HttpServletRequest#getInputStream() y #getReader().

InputStream body = request.getInputStream(); 
// ... 

Tenga en cuenta que solo puede leerlo una vez. El cliente no va a volver a enviarlo varias veces. Llamar al getParameter() y así sucesivamente también lo leerá implícitamente. Tienes que guardar el cuerpo en algún lugar y procesarte a ti mismo.

+3

¿Entonces su respuesta es que hay * ninguna * forma de hacer lo que quiero hacer? No se trata de que el cliente lo envíe más de una vez. El HttpServletRequest almacena claramente los datos de la publicación internamente en algún lugar (ya que siempre puede obtener los parámetros de la publicación varias veces). Agradezco la respuesta, solo quiero entender completamente si dices "es imposible" o si solo estás reiterándote lo que ya he descubierto. –

+11

En la primera llamada 'getParameter()', 'HttpServletRequest' usará internamente' getInputStream() 'para leer y analizar el cuerpo de la solicitud (es una transmisión de bytes desde una conexión de red) y almacenarlo en un mapa que puede obtener 'getParameterMap()'. Después de este punto, ya no puede leer el cuerpo de la solicitud mediante 'getInputStream()'/'getReader()', porque ya se ha leído. Si aclara el requisito funcional detrás de esta necesidad, entonces podemos sugerirle mejores formas de lograrlo. – BalusC

+0

Tenemos un sistema de tamaño mediano que pasa alrededor de objetos HttpServletRequest en todas partes, y hemos tenido formas menos precisas de mostrar lo que son los datos de publicación (anteriormente hemos utilizado una técnica que compara el mapa de parámetros con la cadena de consulta y asume la diferencia es datos de correos). La mayoría de estas cosas son registros internos, pero también tenemos un caso en el que un socio nos envía xml como datos de publicación. En este caso, usar getReader para obtener los datos de la publicación a veces arruinará nuestro registro, y algunas veces nuestro registro puede arruinar el manejo de la solicitud real. –

6

Tuvimos una situación en la que IE nos forzó a publicar como texto/normal, por lo que tuvimos que analizar manualmente los parámetros usando getReader. El servlet se estaba utilizando para un sondeo largo, por lo que cuando se ejecutó AsyncContext :: dispatch después de un retraso, literalmente se volvió a publicar la solicitud con las manos vacías.

Así que acabo de almacenar la publicación en la solicitud cuando apareció por primera vez utilizando HttpServletRequest :: setAttribute. El método getReader vacía el búfer, donde getParameter vacía el búfer también, pero almacena los parámetros automágicamente.

String input = null; 

    // we have to store the string, which can only be read one time, because when the 
    // servlet awakens an AsyncContext, it reposts the request and returns here empty handed 
    if ((input = (String) request.getAttribute("com.xp.input")) == null) { 
     StringBuilder buffer = new StringBuilder(); 
     BufferedReader reader = request.getReader(); 

     String line; 
     while((line = reader.readLine()) != null){ 
      buffer.append(line); 
     } 
     // reqBytes = buffer.toString().getBytes(); 

     input = buffer.toString(); 
     request.setAttribute("com.xp.input", input); 
    } 

    if (input == null) { 
     response.setContentType("text/plain"); 
     PrintWriter out = response.getWriter(); 
     out.print("{\"act\":\"fail\",\"msg\":\"invalid\"}"); 
    }  
Cuestiones relacionadas