Проблема Callable заключается в том, что сам сервлет диспетчера запускает асинхронную обработку и фильтр закрывается до фактической обработки запроса.
Когда Callable прибывает в сервлет диспетчера, он освобождает поток контейнера из пула, освобождая всефильтры (фильтры в основном заканчивают свою работу). Когда Callable дает результаты, сервлет диспетчера вызывается снова с тем же запросом, и ответ незамедлительно выполняется при возврате данных из Callable. Это обрабатывается атрибутом запроса типа AsyncTaskManager
, который содержит некоторую информацию об обработке асинхронного запроса. Это может быть проверено с Filter
и HandlerInterceptor
. Filter
выполняется только один раз, но HandlerInterceptor
выполняется дважды (исходный запрос и запрос после Callable завершает свою работу)
Когда вам нужно прочитать запрос и ответ, одно из решений - переписать dispatcherServlet, какthis:
@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();
}
};
}
Таким образом вы гарантируете, что можете прочитать запрос и ответ несколько раз. Другой способ - добавить 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()
.
Это одно из возможных решений, и могут быть более эффективные способы. .