首页 > 解决方案 > 是否可以在 Spring Boot 中读取响应的正文?

问题描述

我有一个PrintWriterfrom an HttpServletResponse,我想知道是否有任何方法可以读取它的缓冲区(考虑到HttpServletResponse.getWriter()PrintWriter 不是自动刷新的)。

我知道有一些方法可以将 InputStream 转换为 OutputStream,InputStream.transferTo()但是有没有其他方法可以将我的 PrintWriter 转换为任何类型的 OutputStream?或者有什么方法可以读取一个响应体HttpServletResponse

到目前为止,我已经尝试过toString()没有被覆盖的方法。我试图通过不同的流(如PipedInputStream和)来传递它ByteArrayOutputStream

顺便说一句,我正在使用 Spring Boot 微服务架构。

标签: javaspringspring-bootio

解决方案


我终于找到了一种通过spring bootFilter通过覆盖来处理这个问题的方法HttpServletResponseWrapper。所以这是我的代码(覆盖将HttpServletResponseWrapper响应默认输出流更改为我的自定义的类ServletOutputStream):

public class HttpServletResponseCopier extends HttpServletResponseWrapper {

    private ServletOutputStreamCopier copier;
    private ServletOutputStream outputStream;
    private PrintWriter writer;

    /**
     * @param response
     */
    public HttpServletResponseCopier(HttpServletResponse response) {
        super(response);
    }

    @Override
    public ServletOutputStream getOutputStream() throws IOException
    {
        if (outputStream != null)
            throw new IOException("output stream already called for this response");
        else {
            outputStream = getResponse().getOutputStream();
            copier = new ServletOutputStreamCopier(this.outputStream);
            return copier;
        }
    }

    @Override
    public PrintWriter getWriter() throws IOException
    {
        if (outputStream != null)
            throw new IOException("print writer already called for this response");
        else {
            outputStream = getResponse().getOutputStream();
            copier = new ServletOutputStreamCopier(outputStream);
            writer = new PrintWriter(new OutputStreamWriter(copier, getResponse().getCharacterEncoding()));
            return writer;
        }
    }

    @Override
    public void flushBuffer() throws IOException
    {
        if (writer != null)
            writer.flush();
        else if (copier != null)
            copier.flush();

    }

    public String getContent()
    {
        String content = "";
        try {
            content = IOUtils.toString(copier.getCopyBuffer(), getResponse().getCharacterEncoding());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return content;
    }

}

和我的 ServletOutputStreamCopier 类(将流的内容复制到 a 中的类ByteArrayOutputStream):

public class ServletOutputStreamCopier extends ServletOutputStream {

    private ServletOutputStream outputStream;
    private ByteArrayOutputStream copier;

    /**
     * 
     */
    public ServletOutputStreamCopier(ServletOutputStream outputStream) {
        super();
        this.outputStream = outputStream;
        this.copier = new ByteArrayOutputStream();
    }

    @Override
    public boolean isReady()
    {
        return this.outputStream.isReady();
    }

    @Override
    public void setWriteListener(WriteListener listener)
    {

    }

    @Override
    public void write(int b) throws IOException
    {
        if (this.copier == null)
            this.copier = new ByteArrayOutputStream();
        if (this.outputStream == null)
            throw new IOException("outputStream is null");
        this.copier.write(b);
        this.outputStream.write(b);

    }

    public byte[] getCopyBuffer()
    {
        return this.copier.toByteArray();
    }

}

最后将其注入弹簧靴过滤器:

@Component
public class LoggingFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(
        HttpServletRequest request,
        HttpServletResponse response,
        FilterChain filterChain
    ) throws ServletException, IOException
    {
        HttpServletResponseCopier responseWrapper = new HttpServletResponseCopier(response);
        filterChain.doFilter(request, responseWrapper);

        System.out.println("response body: "+responseWrapper.getContent());

    }
}

输出这个:

"body": <response body here>

推荐阅读