Spring MVC与Spring Boot中Filter日志打印陷阱与解决方案

3 下载量 153 浏览量 更新于2024-09-01 收藏 69KB PDF 举报
"本文将深入探讨在Spring MVC和Spring Boot应用中如何利用Filter来打印请求参数,以及在处理过程中可能遇到的问题和解决方案。" 在Spring MVC和Spring Boot框架中,Filter是一个重要的组件,用于在HTTP请求被实际处理之前或之后执行特定的操作,如身份验证、日志记录等。在不使用AOP的情况下,我们可以通过自定义Filter来记录请求和响应的详细信息,包括请求参数。然而,直接在Filter中打印JSON类型的请求参数可能会导致错误。 首先,让我们看看错误的Filter实现方式。通常,我们会继承`OncePerRequestFilter`类,因为它能确保每个请求只被过滤一次,防止重复处理。一个简单的错误示例是: ```java @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { filterChain.doFilter(request, response); printRequestLog(request); printResonseLog(response); } ``` 在这个例子中,`filterChain.doFilter()`方法会继续调用下一个Filter或者控制器,然后尝试读取或处理请求和响应。但是,当请求的`Content-Type`是`application/json`且使用POST方法发送JSON数据时,这样做会导致异常,如`java.io.IOException: Stream closed`。这是因为请求体被读取一次后,流就被关闭了,所以后续尝试再次读取时会抛出异常。 为了解决这个问题,我们需要在过滤器中保存请求体的副本,以便后续可以安全地访问。一种解决方案是使用`HttpServletRequestWrapper`和`HttpServletResponseWrapper`来复制原始请求和响应,然后在过滤器中操作这些副本。以下是一个修正后的示例: ```java public class LoggingFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { HttpServletRequest wrapperRequest = new HttpServletRequestWrapper(request) { private byte[] requestBody; @Override public ServletInputStream getInputStream() throws IOException { if (requestBody == null) { requestBody = IOUtils.toByteArray(super.getInputStream()); } return new ServletInputStreamImpl(new ByteArrayInputStream(requestBody)); } }; HttpServletResponse wrapperResponse = new HttpServletResponseWrapper(response) { // 对响应的处理类似,保存并重写getOutputStream() }; filterChain.doFilter(wrapperRequest, wrapperResponse); // 此时,可以安全地读取并打印请求和响应 printRequestLog(wrapperRequest); printResonseLog(wrapperResponse); } // 实现printRequestLog和printResonseLog方法,用于记录日志 } ``` 在这个修正后的实现中,我们创建了自定义的`HttpServletRequestWrapper`,在首次调用`getInputStream()`时,将请求体内容保存到内存中。这样,我们可以在过滤器的最后阶段安全地读取和打印请求参数,而不会影响原始请求流。 正确处理JSON请求参数的Filter应该避免直接读取和修改原始请求和响应流,而是使用Wrapper类来复制流,并在需要的时候访问它们。这个技巧不仅适用于Spring MVC,也适用于Spring Boot,确保在过滤请求和响应时能够准确记录日志,同时避免出现异常。