如何读取和复制 HTTP servlet 响应输出流内容以进行日志记录
2022-08-31 17:07:23
我已经在我的java Web服务器(实际上是appengine)中创建了一个过滤器,用于记录传入请求的参数。我还想记录我的Web服务器写入的结果响应。虽然我可以访问响应对象,但我不确定如何从中获取实际的字符串/内容响应。
有什么想法吗?
我已经在我的java Web服务器(实际上是appengine)中创建了一个过滤器,用于记录传入请求的参数。我还想记录我的Web服务器写入的结果响应。虽然我可以访问响应对象,但我不确定如何从中获取实际的字符串/内容响应。
有什么想法吗?
您需要创建一个过滤器,
其中使用自定义的HttpServletResponseWrapper
实现包装参数,其中您可以覆盖并返回自定义ServletOutputStream
实现,其中您复制基本抽象的ProstoutStream#write(int b)
方法中的写入字节。然后,将包装的自定义传递给调用,最后您应该能够在调用后获得复制的响应。ServletResponse
getOutputStream()
getWriter()
HttpServletResponseWrapper
FilterChain#doFilter()
换句话说,:Filter
@WebFilter("/*")
public class ResponseLogger implements Filter {
@Override
public void init(FilterConfig config) throws ServletException {
// NOOP.
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
if (response.getCharacterEncoding() == null) {
response.setCharacterEncoding("UTF-8"); // Or whatever default. UTF-8 is good for World Domination.
}
HttpServletResponseCopier responseCopier = new HttpServletResponseCopier((HttpServletResponse) response);
try {
chain.doFilter(request, responseCopier);
responseCopier.flushBuffer();
} finally {
byte[] copy = responseCopier.getCopy();
System.out.println(new String(copy, response.getCharacterEncoding())); // Do your logging job here. This is just a basic example.
}
}
@Override
public void destroy() {
// NOOP.
}
}
定制:HttpServletResponseWrapper
public class HttpServletResponseCopier extends HttpServletResponseWrapper {
private ServletOutputStream outputStream;
private PrintWriter writer;
private ServletOutputStreamCopier copier;
public HttpServletResponseCopier(HttpServletResponse response) throws IOException {
super(response);
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
if (writer != null) {
throw new IllegalStateException("getWriter() has already been called on this response.");
}
if (outputStream == null) {
outputStream = getResponse().getOutputStream();
copier = new ServletOutputStreamCopier(outputStream);
}
return copier;
}
@Override
public PrintWriter getWriter() throws IOException {
if (outputStream != null) {
throw new IllegalStateException("getOutputStream() has already been called on this response.");
}
if (writer == null) {
copier = new ServletOutputStreamCopier(getResponse().getOutputStream());
writer = new PrintWriter(new OutputStreamWriter(copier, getResponse().getCharacterEncoding()), true);
}
return writer;
}
@Override
public void flushBuffer() throws IOException {
if (writer != null) {
writer.flush();
} else if (outputStream != null) {
copier.flush();
}
}
public byte[] getCopy() {
if (copier != null) {
return copier.getCopy();
} else {
return new byte[0];
}
}
}
定制:ServletOutputStream
public class ServletOutputStreamCopier extends ServletOutputStream {
private OutputStream outputStream;
private ByteArrayOutputStream copy;
public ServletOutputStreamCopier(OutputStream outputStream) {
this.outputStream = outputStream;
this.copy = new ByteArrayOutputStream(1024);
}
@Override
public void write(int b) throws IOException {
outputStream.write(b);
copy.write(b);
}
public byte[] getCopy() {
return copy.toByteArray();
}
}
BalusC解决方案还可以,但有点过时。春天现在有它的功能 。您需要做的就是使用 ,它具有 方法 。[ContentCachingResponseWrapper]
public byte[] getContentAsByteArray()
我建议制作WrapprFactory,这将允许它可配置,无论是使用默认的RecertWrapper还是ContentCachingResponseWrapper。