Как исключить ClientAbortException из SimpleMappingExceptionResolver - PullRequest
13 голосов
/ 25 ноября 2011

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

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

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

<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>

Ответы [ 3 ]

10 голосов
/ 15 декабря 2011

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

2 голосов
/ 31 марта 2016

Для более новых версий 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());
    }

}
1 голос
/ 15 января 2013

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...