【问题标题】:Spring MVC - Get HttpServletResponse bodySpring MVC - 获取 HttpServletResponse 主体
【发布时间】:2019-02-06 08:46:13
【问题描述】:

由于 2 天后我仍然不知道如何在 HandlerInterceptorAdapter 中打印 HttpServletResponse 正文,我会再问一次 :)

使用HttpServletRequest,我可以轻松地做类似request.getReader().lines().collect(Collectors.joining(System.lineSeparator())); 的事情,而且我拥有完整的身体,但如何使用HttpServletResponse 做同样的事情?

我在 StackOverflow 上发现了很多关于此的问题,但似乎没有一个有效。

这是处理程序:

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
        throws Exception {
    //how to print here the "response" by using the "response" parameter
    super.afterCompletion(request, response, handler, ex);
}

this 答案完全相同,并链接到this,但他们使用ServletResponse 而不是HttpServletResponse 以及FilterChain 的东西,我的afterCompletion 处理程序中没有。即使是看起来最完整的this 也不适合(我认为)我的情况。

谁能给我一个简单的序列化例子HttpServletResponse

【问题讨论】:

  • 您好 Faraz Durrani 感谢您的回复。我正在寻找如何打印正文响应,而不是请求。

标签: java spring-mvc servlets


【解决方案1】:

简单的答案是“你不能在 Handler Interceptor 中做到这一点”。 Says so in the manual

HandlerInterceptor 基本上类似于 Servlet 过滤器,但与后者相比,它只允许自定义预处理和禁止处理程序本身执行的选项,以及自定义后处理。 过滤器更强大,例如它们允许交换传递链的请求和响应对象。请注意,过滤器是在 web.xml 中配置的,它是应用程序上下文中的 HandlerInterceptor。

作为基本准则,与处理程序相关的细粒度预处理任务是 HandlerInterceptor 实现的候选对象,尤其是分解出的通用处理程序代码和授权检查。另一方面,过滤器非常适合请求内容和查看内容处理,例如多部分表单和 GZIP 压缩。这通常显示何时需要将过滤器映射到某些内容类型(例如图像)或所有请求。

因此,正如您所指出的,我建议您查看基于过滤器的解决方案。您可能对:ContentCachingResponseWrapper Produces Empty Response 感兴趣,这似乎可以用最少的编码完成您想要的。但是,一旦您开始使用过滤器,您在问题中链接到的任何被广泛接受的答案都可能会起作用。

【讨论】:

  • 您好 GPI 感谢您提供有用的答案。很清楚为什么这不是一个好方法,但尝试 OncePerRequestFilter 或 Filter 似乎在控制器执行后不会调用 doFilterInternal 或 doFilter 。我应该改用什么?
  • 我猜如果你的过滤器的方法没有被调用,那可能是因为 Spring 没有拾取并部署它们。因此,您可能应该阅读手册以查看“如何注册过滤器”。如果您使用纯 SpringBoot 应用程序,与嵌入 Spring 上下文的 Servlet webapp 相比,这样做的方式是不同的,...所以请阅读相关文档。
【解决方案2】:

很难深入研究它,但发现ResponseBodyAdvice 可能适合我的目的。因此,在 StackOverflow 上寻找一些示例,发现 this 的人在操作 Object body 时遇到了完全相同的问题。

为了实现我写的here,这是我最终的工作解决方案

@ControllerAdvice
public class CSRFHandler implements ResponseBodyAdvice<Object> {

    @Value("${security.csrf.enabled}")
    private String csrfEnabled;

    @Value("${security.csrf.headerName}")
    private String csrfHeaderName;

    @Value("${security.csrf.salt}")
    private String salt;

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
            Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request,
            ServerHttpResponse response) {

        if (new Boolean(csrfEnabled).booleanValue()) {
            String csrfValue = SecureUtil.buildCsrfValue(salt, StringUtil.toJson(body));
            response.getHeaders().add(csrfHeaderName, csrfValue);
        }

        return body;
    }

}

【讨论】:

    【解决方案3】:

    我在 Kotlin 中得到了以下结果:

    @Bean
    open fun logFilter(): CommonsRequestLoggingFilter {
        val filter = InfoRequestLoggingFilter()
        filter.setIncludeQueryString(true)
        filter.setIncludePayload(true)
        filter.setMaxPayloadLength(10000)
        filter.isIncludeHeaders = false
        return filter
    }
    
    import org.apache.commons.io.output.TeeOutputStream
    import org.springframework.mock.web.DelegatingServletOutputStream
    import org.springframework.web.filter.CommonsRequestLoggingFilter
    import java.io.ByteArrayOutputStream
    import java.io.IOException
    import java.io.PrintStream
    import java.io.PrintWriter
    import javax.servlet.FilterChain
    import javax.servlet.ServletOutputStream
    import javax.servlet.http.HttpServletRequest
    import javax.servlet.http.HttpServletResponse
    import javax.servlet.http.HttpServletResponseWrapper
    
    class InfoRequestLoggingFilter : CommonsRequestLoggingFilter() {
    
        override fun beforeRequest(request: HttpServletRequest, message: String) {
            logger.info(message)
        }
    
        override fun afterRequest(request: HttpServletRequest, message: String) {
            // logger.info(message) - NOP, since doFilterInternal is logging it instead
        }
    
        override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, filterChain: FilterChain) {
    
            val outputStream = ByteArrayOutputStream()
            val printStream = PrintStream(outputStream)
    
            filterChain.doFilter(request, object : HttpServletResponseWrapper(response) {
                @Throws(IOException::class)
                override fun getOutputStream(): ServletOutputStream {
                    return DelegatingServletOutputStream(TeeOutputStream(super.getOutputStream(), printStream)
                    )
                }
    
                @Throws(IOException::class)
                override fun getWriter(): PrintWriter {
                    return PrintWriter(DelegatingServletOutputStream(TeeOutputStream(super.getOutputStream(), printStream))
                    )
                }
            })
    
            logger.info(String.format("%s ;status=%s ;payload=%s", createMessage(request, "", ""), response.status, outputStream.toString()))
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-03
      • 1970-01-01
      • 1970-01-01
      • 2013-01-27
      • 2019-06-29
      • 2015-07-13
      • 2018-11-10
      相关资源
      最近更新 更多