如何读取和复制 HTTP servlet 响应输出流内容以进行日志记录 [英] How to read and copy the HTTP servlet response output stream content for logging

查看:80
本文介绍了如何读取和复制 HTTP servlet 响应输出流内容以进行日志记录的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的 java 网络服务器(实际上是 appengine)中创建了一个过滤器,用于记录传入请求的参数.我还想记录我的网络服务器写入的结果响应.尽管我可以访问响应对象,但我不确定如何从中获取实际的字符串/内容响应.

I've created a filter to in my java webserver (appengine actually) that logs the parameters of an incoming request. I'd also like to log the resulting response that my webserver writes. Although I have access to the response object, I'm not sure how to get the actual string/content response out of it.

有什么想法吗?

推荐答案

你需要创建一个Filter,其中使用自定义 HttpServletResponseWrapper 实现,其中覆盖 getOutputStream()getWriter() 以返回一个自定义 ServletOutputStream 实现,其中您复制基础摘要中写入的字节 OutputStream#write(int b) 方法.然后,您将封装的自定义 HttpServletResponseWrapper 传递给 FilterChain#doFilter() 调用,最后您应该能够在 after 之后获得复制的响应电话.

You need to create a Filter wherein you wrap the ServletResponse argument with a custom HttpServletResponseWrapper implementation wherein you override the getOutputStream() and getWriter() to return a custom ServletOutputStream implementation wherein you copy the written byte(s) in the base abstract OutputStream#write(int b) method. Then, you pass the wrapped custom HttpServletResponseWrapper to the FilterChain#doFilter() call instead and finally you should be able to get the copied response after the the call.

换句话说,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();
    }

}

这篇关于如何读取和复制 HTTP servlet 响应输出流内容以进行日志记录的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆