2011-06-12 8 views
8

Estoy intentando crear un registro de solicitud para mi aplicación web. Estoy utilizando resorte 3. 0.Logging HttpRequest parameters and request body

he implementado una clase que se extiende HandlerInterceptorAdapter y utilizamos el preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) para interceptar la petición.

En el método Quiero ser capaz de registrar el cuerpo de la petición (mis parámetros son objetos en XML que se escriben directamente en el cuerpo de la petición), y para que yo uso request.getReader();

El problema es - más adelante Obtendré un IllegalStateException cuando el controlador de primavera intente leer la solicitud.

¿Hay alguna manera de hacer lo que pretendo?

+0

Hay un par de problemas. En ServletRequest solo puede llamar a getReader() o getInputStream() no a ambos. Si llamas a ambos, obtienes una IllegalStateException. Podría intentar llamar a getInputStream, pero aún así puede obtener un error si lee la secuencia de entrada. Es posible que Spring no pueda verla. (ServletInputStream puede ser compatible con el reinicio, pero no lo creo). Su mejor opción es registrar los parámetros durante el proceso de deserialización XML (debe averiguar qué clase hace esto) o inmediatamente después. – Pace

+0

¿ha considerado configurar su servidor http para registrar los encabezados de solicitud o usar filtros de servlet para realizar el registro? – happymeal

+0

@happymeal No solo necesito los encabezados, también necesito el cuerpo. –

Respuesta

5

Puede hacer esto con un filtro. Los parámetros de solicitud son fáciles de manejar. Sin embargo, tratar con el cuerpo de la solicitud será mucho más difícil y requerirá el ajuste de la solicitud de servlet ver: HttpServletRequest.

Tendrá que ver qué tan grande es la solicitud entrante y decidir si desea almacenar el cuerpo de la solicitud como un archivo o cadena tmp.

Deberá anular ServetRequest.getInputStream() con su archivo o cadena guardada que se utilizó para el registro.

Si el cuerpo de la solicitud es enorme, recomiendo poner el flujo de entrada en un flujo de entrada en el búfer y luego leer el inicio del cuerpo.

public class LogRequest extends HttpServletRequestWrapper { 

    public LogRequest(HttpServletRequest request) { 
     super(request); 
    } 

    @Override 
    public ServletInputStream getInputStream() throws IOException { 
     //read from tmp file or string. 
    } 

    @Override 
    public BufferedReader getReader() throws IOException { 
     //read from tmp file or string 
    } 

} 
+0

Envolver la solicitud todavía no me permite llamar 'getReader()' dos veces. Todavía obtengo la excepción StateState –

+0

. Noam Nevo va a llamar a los métodos de entrada (reader/inputstream) en la solicitud original y luego ajusta la solicitud original con el contenedor de solicitudes con getReader() y amigos anulados. –

4

primavera tiene un filtro dispuesto a hacer eso para usted - ver el uso de AbstractRequestLoggingFilter y sus subclases se describe en this answer.

Tenga en cuenta que al usar esta solución, el cuerpo de la solicitud se registrará solo después de que se complete el procesamiento de la solicitud y su cuerpo haya leído el cuerpo.

+1

AbstractRequestLoggingFilter no le permitirá registrar la solicitud antes de que se haya procesado.No puede obtener la carga útil en AbstractRequestLoggingFilter # beforeRequest. Si está bien para usted, puede anular AbstractRequestLoggingFilter # afterRequest que registrará todo, incluida la carga útil. –

0

Implementación simple para pequeñas solicitudes. No lo use para solicitud de partes múltiples.

package ru.rbs.logger.web; 

import org.apache.commons.io.IOUtils; 

import javax.servlet.ReadListener; 
import javax.servlet.ServletInputStream; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletRequestWrapper; 
import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 

class CachedRequestWrapper extends HttpServletRequestWrapper { 
    private final byte[] cachedBody; 

    CachedRequestWrapper(HttpServletRequest request) throws IOException { 
     super(request); 

     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     IOUtils.copy(request.getInputStream(), bos); 
     cachedBody = bos.toByteArray(); 
    } 

    @Override 
    public ServletInputStream getInputStream() throws IOException { 
     return new CachedServletInputStream(); 
    } 

    byte[] toByteArray(){ 
     return cachedBody; 
    } 

    private class CachedServletInputStream extends ServletInputStream { 
     private InputStream baseInputStream; 

     CachedServletInputStream() throws IOException { 
      baseInputStream = new ByteArrayInputStream(cachedBody); 
     } 

     @Override 
     public boolean isFinished() { 
      return false; 
     } 

     @Override 
     public boolean isReady() { 
      return false; 
     } 

     @Override 
     public void setReadListener(ReadListener readListener) { 

     } 

     @Override 
     public int read() throws IOException { 
      return baseInputStream.read(); 
     } 
    } 
}