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?
views:
99answers:
3If 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 GET
s and POST
s):
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.
Maybe a servlet filter can help you. Think of it as aspect-oriented programming for HTTP.
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.