亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

讀取異步請求中的響應正文

讀取異步請求中的響應正文

搖曳的薔薇 2024-01-05 14:47:58
我想知道如果 @Controller 方法返回 Callable 接口,如何從請求正文中讀取過濾器中的響應。我的過濾器看起來像這樣。響應始終為空。有什么辦法解決這個問題嗎?僅使用 AsyncListener 才允許這樣做嗎?@Componentpublic class ResposeBodyXmlValidator extends OncePerRequestFilter {    private final XmlUtils xmlUtils;    private final Resource xsdResource;    public ResposeBodyXmlValidator(        XmlUtils xmlUtils,        @Value("classpath:xsd/some.xsd") Resource xsdResource    ) {        this.xmlUtils = xmlUtils;        this.xsdResource = xsdResource;    }    @Override    protected void doFilterInternal(        HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain    ) throws ServletException, IOException {        ContentCachingResponseWrapper response = new ContentCachingResponseWrapper(httpServletResponse);        doFilter(httpServletRequest, response, filterChain);        if (MediaType.APPLICATION_XML.getType().equals(response.getContentType())) {            try {                xmlUtils.validate(new String(response.getContentAsByteArray(), response.getCharacterEncoding()), xsdResource.getInputStream());            } catch (IOException | SAXException e) {                String exceptionString = String.format("Chyba p?i volání %s\nNevalidní vystupní XML: %s",                    httpServletRequest.getRemoteAddr(),                    e.getMessage());                response.setContentType(MediaType.TEXT_PLAIN_VALUE + "; charset=UTF-8");                response.setCharacterEncoding(StandardCharsets.UTF_8.name());                response.getWriter().print(exceptionString);            }        }        response.copyBodyToResponse(); // I found this needs to be added at the end of the filter    }}
查看完整描述

1 回答

?
德瑪西亞99

TA貢獻1770條經驗 獲得超3個贊

Callable 的問題在于調度程序 servlet 本身會啟動異步處理,并且過濾器會在實際處理請求之前退出。


當 Callable 到達調度程序 servlet 時,它通過釋放所有過濾器(過濾器基本上完成其工作)來從池中釋放容器線程。當 Callable 產生結果時,會使用相同的請求再次調用調度程序 servlet,并且響應會立即由 Callable 返回的數據完成。這是由類型的 request 屬性處理的,AsyncTaskManager該屬性保存有關異步請求處理的一些信息。這可以用Filter和進行測試HandlerInterceptor。Filter只執行一次但HandlerInterceptor執行了兩次(原始請求和Callable完成工作后的請求)


當您需要讀取請求和響應時,解決方案之一是像這樣重寫dispatcherServlet:


@Bean

@Primary

public DispatcherServlet dispatcherServlet(WebApplicationContext context) {

    return new DispatcherServlet(context) {

        @Override

        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

            ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);

            ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);

            super.service(requestWrapper, responseWrapper);

            responseWrapper.copyBodyToResponse();

        }

    };

}

這樣您就可以確??梢远啻巫x取請求和響應。另一件事是像這樣添加 HandlerInterceptor (您必須傳遞一些數據作為請求屬性):


    @Override

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws

        Exception {

        Object asyncRequestData = request.getAttribute(LOGGER_FILTER_ATTRIBUTE);

        if (asyncRequestData == null) {

            request.setAttribute(LOGGER_FILTER_ATTRIBUTE, new AsyncRequestData(request));

        }

        return true;

    }


    @Override

    public void afterCompletion(

        HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex

    ) throws Exception {

        Object asyncRequestData = request.getAttribute(LOGGER_FILTER_ATTRIBUTE);

        if (asyncRequestData != null && response instanceof ContentCachingResponseWrapper) {

            log(request, (ContentCachingResponseWrapper) response, (AsyncRequestData) asyncRequestData);

        }

    }

afterCompletion方法僅在異步請求完全處理后調用一次。preHandle被調用兩次,因此您必須檢查屬性是否存在。在afterCompletion中,調用的響應已經存在,如果您確實想要替換它,您應該調用response.resetBuffer().


這是一種可能的解決方案,并且可能有更好的方法。


查看完整回答
反對 回復 2024-01-05
  • 1 回答
  • 0 關注
  • 156 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號