Ответ 1
Расширить SimpleMappingExceptionResolver
, переопределить метод doResolveException()
, а в случае, если имя исключения ClientAbortException
и response.isCommitted()
возвращает null
вместо возврата super.doResolveException()
.
Я использую 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>
Расширить SimpleMappingExceptionResolver
, переопределить метод doResolveException()
, а в случае, если имя исключения ClientAbortException
и response.isCommitted()
возвращает null
вместо возврата super.doResolveException()
.
IMHO, регистрация вида nothing
для Exception
, который вы не хотите обрабатывать, является элегантным способом; в отличие от чувства взлома; так как у вас может быть более одного исключения, вы не будете/не хотите рендерить по сравнению с другими исключениями.
Я не рекомендую придумывать специальную реализацию для HandlerExceptionResolver; поскольку это может увеличить затраты на ремонтопригодность.
Для более новых версий 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());
}
}