Spring MVC-获取HttpServletResponse正文

时间:2018-08-31 10:23:12

标签: java spring-mvc servlets

由于两天后,我仍然无法弄清楚如何在HttpServletResponse中打印HandlerInterceptorAdapter正文,所以我会再问一次:)

有了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为我提供一个简单的序列化示例吗?

3 个答案:

答案 0 :(得分:2)

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

  

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

     

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

因此,正如您所指出的,我建议您检查基于过滤器的解决方案。您可能对以下内容感兴趣:ContentCachingResponseWrapper Produces Empty Response,它似乎可以用最少的编码来完成所需的工作。但是,一旦您开始使用过滤器,您在问题中链接到的任何公认的答案都可能会成功。

答案 1 :(得分:1)

很难深入研究它,但发现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;
    }

}

答案 2 :(得分:0)

我在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()))
    }
}