簡體   English   中英

Spring MVC-獲取HttpServletResponse正文

[英]Spring MVC - Get HttpServletResponse body

由於兩天后,我仍然無法弄清楚如何在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);
}

這個答案是完全相同的,並鏈接到此,但是它們使用ServletResponse和NOT HttpServletResponse以及帶有FilterChain東西,而我在afterCompletion處理程序中沒有。 就我而言,即使似乎是最完整的,也不適合。

有人可以為我提供一個簡單的HttpServletResponse序列化示例嗎?

簡單的答案是“您不能在處理程序攔截器中做到這一點”。 在手冊中這樣說

HandlerInterceptor基本上類似於Servlet過濾器,但與后者相比,它僅允許自定義預處理以及禁止執行處理程序本身和自定義后處理的選項。 過濾器功能更強大,例如,它們允許交換傳遞到鏈中的請求和響應對象 請注意,在應用程序上下文中的HandlerInterceptor web.xml中配置了過濾器。

作為基本准則, 與處理程序相關的細粒度預處理任務是HandlerInterceptor實現的候選對象,尤其是分解出的公共處理程序代碼和授權檢查。 另一方面,過濾器非常適合請求內容和視圖內容處理 ,例如多部分表單和GZIP壓縮。 這通常顯示何時需要將過濾器映射到某些內容類型(例如圖像)或所有請求。

因此,我建議您像您指出的那樣,檢查基於過濾器的解決方案。 您可能對以下內容感興趣: ContentCachingResponseWrapper產生空響應 ,似乎可以用最少的編碼來完成所需的操作。 但是,一旦您開始使用過濾器,您在問題中鏈接到的任何公認的答案都可能會起作用。

很難深入研究它,但是發現ResponseBodyAdvice可能適合我的目的。 因此,在StackOverflow上查找一些示例時,發現這個家伙不得不操縱Object body也存在同樣的問題。

那是我最終實現我在這里寫的工作解決方案

@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;
    }

}

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM