1 回答

TA貢獻(xiàn)1770條經(jīng)驗(yàn) 獲得超3個(gè)贊
Callable 的問題在于調(diào)度程序 servlet 本身會(huì)啟動(dòng)異步處理,并且過濾器會(huì)在實(shí)際處理請(qǐng)求之前退出。
當(dāng) Callable 到達(dá)調(diào)度程序 servlet 時(shí),它通過釋放所有過濾器(過濾器基本上完成其工作)來從池中釋放容器線程。當(dāng) Callable 產(chǎn)生結(jié)果時(shí),會(huì)使用相同的請(qǐng)求再次調(diào)用調(diào)度程序 servlet,并且響應(yīng)會(huì)立即由 Callable 返回的數(shù)據(jù)完成。這是由類型的 request 屬性處理的,AsyncTaskManager該屬性保存有關(guān)異步請(qǐng)求處理的一些信息。這可以用Filter和進(jìn)行測試HandlerInterceptor。Filter只執(zhí)行一次但HandlerInterceptor執(zhí)行了兩次(原始請(qǐng)求和Callable完成工作后的請(qǐng)求)
當(dāng)您需要讀取請(qǐng)求和響應(yīng)時(shí),解決方案之一是像這樣重寫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取請(qǐng)求和響應(yīng)。另一件事是像這樣添加 HandlerInterceptor (您必須傳遞一些數(shù)據(jù)作為請(qǐng)求屬性):
@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方法僅在異步請(qǐng)求完全處理后調(diào)用一次。preHandle被調(diào)用兩次,因此您必須檢查屬性是否存在。在afterCompletion中,調(diào)用的響應(yīng)已經(jīng)存在,如果您確實(shí)想要替換它,您應(yīng)該調(diào)用response.resetBuffer().
這是一種可能的解決方案,并且可能有更好的方法。
添加回答
舉報(bào)