servletoutputstream httpservletresponse body java servlets

java - servletoutputstream - httpservletresponse get body



Captura y registra el cuerpo de la respuesta (3)

Tengo un servlet que maneja ciertas solicitudes y respuestas HTTP. Quiero registrar el cuerpo de respuesta antes de enviarlo de vuelta al cliente. ¿Hay alguna manera de que pueda capturar el cuerpo de la respuesta antes de que se envíe como un objeto HttpServletResponse desde el servlet?


Si te entiendo correctamente, ¿quieres registrar el cuerpo de respuesta? Esa es una tarea bastante costosa, pero si ese es el requisito del negocio ...

Como @duffymo señaló, un Filter es un lugar adecuado para esto. Puede capturar el cuerpo de la respuesta reemplazando la implementación HttpServletResponseWrapper ServletResponse con una implementación HttpServletResponseWrapper que reemplaza la HttpServletResponse#getWriter() con una implementación propia que copia el cuerpo de la respuesta en algún búfer. Después de continuar la cadena de filtros con la respuesta reemplazada, simplemente registre la copia.

Aquí hay un ejemplo de cómo el método doFilter() puede verse:

public void doFilter(ServletRequest request, final ServletResponse response, FilterChain chain) throws IOException, ServletException { final CopyPrintWriter writer = new CopyPrintWriter(response.getWriter()); chain.doFilter(request, new HttpServletResponseWrapper((HttpServletResponse) response) { @Override public PrintWriter getWriter() { return writer; } }); logger.log(writer.getCopy()); }

Así es como puede verse el CopyPrintWriter :

public class CopyPrintWriter extends PrintWriter { private StringBuilder copy = new StringBuilder(); public CopyPrintWriter(Writer writer) { super(writer); } @Override public void write(int c) { copy.append((char) c); // It is actually a char, not an int. super.write(c); } @Override public void write(char[] chars, int offset, int length) { copy.append(chars, offset, length); super.write(chars, offset, length); } @Override public void write(String string, int offset, int length) { copy.append(string, offset, length); super.write(string, offset, length); } public String getCopy() { return copy.toString(); } }

Asigne este filtro en un url-pattern de url-pattern para el que le gustaría registrar las respuestas. Tenga en cuenta que el contenido binario / estático como imágenes, CSS, archivos JS, etc., no se registrará de esta manera. Le gustaría excluirlos utilizando un url-pattern suficientemente específico, por ejemplo, *.jsp o simplemente en el servlet-name de servlet del servlet en cuestión. Si desea registrar contenido binario / estático de todos modos (para el cual no veo ningún beneficio), entonces también debe reemplazar HttpServletResponse#getOutputStream() la misma manera.


Tal vez un filtro servlet te pueda ayudar. Piense en ello como una programación orientada a aspectos para HTTP.


Una alternativa a la respuesta de BalusC Uso de TeeOutputStream para escribir en dos flujos de salida a la vez.

public void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); final PrintStream ps = new PrintStream(baos); chain.doFilter(req,new HttpServletResponseWrapper(res) { @Override public ServletOutputStream getOutputStream() throws IOException { return new DelegatingServletOutputStream(new TeeOutputStream(super.getOutputStream(), ps) ); } @Override public PrintWriter getWriter() throws IOException { return new PrintWriter(new DelegatingServletOutputStream (new TeeOutputStream(super.getOutputStream(), ps)) ); } }); //Get Response body calling baos.toString(); }