Подтвердить что ты не робот

Как исключить исключение ClientAbortException из SimpleMappingExceptionResolver

Я использую SimpleMappingExceptionResolver, который отправляет все исключения в представление, где он красиво отображается. Это работает, за исключением одного случая: Если пользователь запрашивает страницу, а затем отправляет и "Отменяет" (я точно не знаю, как это работает, но я заметил, что если я нажимаю кнопку отправки формы сообщения HTTP очень быстро, и часто Firefox 7 как-то уведомляет сервер, он больше не интересуется результатом.) Затем Tomcat 6 поднимает ClientAbortException, когда пытается сделать страницу, или напишите ответ http в любом виде.

Теперь начинается проблема: SimpleMappingExceptionResolver "ловит" исключение и пытается отобразить его на странице html. Затем это вызывает в уже закрытом исключении Stream, который загрязняет файл журнала. (java.lang.IllegalStateException: getOutputStream() has already been called for this response)

То, что я сделал, это зарегистрировать пустую страницу jsp для "ClientAbortException". Но я чувствую, что это хак. С другой стороны, я полагаю, что это не проблема без компромиссов, потому что я ожидаю этого почти в каждом приложении spring, которое отображает все исключения. Так кто-нибудь имеет опыт работы с этой проблемой или имеет представление о не столь хакерском решении?

<bean
  class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"
  p:defaultErrorView="uncaughtException">
    <property name="exceptionMappings">
        <props>
           <prop key=".MissingServletRequestParameterException">
               resourceNotFound
           </prop>
           <prop key=".ClientAbortException">nothing</prop>
        </props>
     </property>
</bean>
4b9b3361

Ответ 1

Расширить SimpleMappingExceptionResolver, переопределить метод doResolveException(), а в случае, если имя исключения ClientAbortException и response.isCommitted() возвращает null вместо возврата super.doResolveException().

Ответ 2

IMHO, регистрация вида nothing для Exception, который вы не хотите обрабатывать, является элегантным способом; в отличие от чувства взлома; так как у вас может быть более одного исключения, вы не будете/не хотите рендерить по сравнению с другими исключениями.

Я не рекомендую придумывать специальную реализацию для HandlerExceptionResolver; поскольку это может увеличить затраты на ремонтопригодность.

Ответ 3

Для более новых версий Spring вы также можете использовать аннотацию @ExceptionHandler, возможно, с @ControllerAdvice (для глобальной обработки).

@ControllerAdvice
public class GlobalDefaultExceptionHandler {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @ExceptionHandler(ClientAbortException.class)
    public void clientAbortExceptionHandler(HttpServletRequest request, ClientAbortException e) {
        // This usually means the browser closed or disconnected or
        // something. We can't do anything. To avoid excessive stack traces
        // in log, just print a simple message and return null
        String username = "<NONE>";
        Principal principal = request.getUserPrincipal();
        if (principal != null) {
            username = principal.getName();
        }
        logger.warn("ClientAbortException: username={},remoteAddr={},userAgent={},requestedURL={}", username,
                request.getRemoteAddr(), request.getHeader("User-Agent"), request.getRequestURL());
    }

}