tags:

views:

99

answers:

3

I have a servlet that handle certain HTTP requests and responses. I want to log the response body before sending back to the client. Is there any way that I can capture the response body before it is send as a HttpServletResponse object from the servlet?

A: 

If I understand your question right, you have access to the HttpResponse object within your servlet if you override methods from the base object (which you would have to do to handle GETs and POSTs):

private void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
   //here it is! --------------------------------------------------^
   //call a service and do stuff with request
   //modify response object however you need to
   //log whatever values from the response object you want       
}

EDIT

See duffymo's answer. A filter might help you out here.

Vivin Paliath
how can i get this response object body?
Jonathan
what do you mean by "response object body"? I'd suggest you look at the API entry for HttpServletResponse.
Catchwa
+1  A: 

Maybe a servlet filter can help you. Think of it as aspect-oriented programming for HTTP.

duffymo
Funny how every other answer cites mine, but it wasn't the accepted one....
duffymo
+3  A: 

If I understand you correctly, you want to log the response body? That's a pretty expensive task, but if that's the business requirement...

As @duffymo pointed, a Filter is a suitable place for this. You can capture the response body by replacing the passed-in ServletResponse with a HttpServletResponseWrapper implementation which replaces the HttpServletResponse#getWriter() with an own implementation which copies the response body into some buffer. After continuing the filter chain with the replaced response, just log the copy.

Here's a kickoff example how the doFilter() method can look like:

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());
}

Here's how the CopyPrintWriter can look like:

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();
    }

}

Map this filter on an url-pattern for which you'd like to log responses for. Keep in mind that binary/static content like images, CSS, JS files and so on won't be logged this way. You'd like to exclude them by using a specific enough url-pattern, e.g. *.jsp or just on the servlet-name of the servlet in question. If you want to log binary/static content anyway (for which I don't see any benefit), then you need to replace the HttpServletResponse#getOutputStream() the same way as well.

BalusC