From 45b8cf350e57d4f545f605b8b50039e2f1c809fc Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Fri, 28 Oct 2016 17:41:48 +0300 Subject: [PATCH] Better handling for AsyncRequestTimeoutException Avoid call to sendError when response is committed and log a short error message instead. Issue: SPR-14739 --- .../ResponseEntityExceptionHandler.java | 20 +++++++++++++++---- .../DefaultHandlerExceptionResolver.java | 8 +++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java index 50f10e4bb9a..0faabda8bc9 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java @@ -18,6 +18,8 @@ package org.springframework.web.servlet.mvc.method.annotation; import java.util.List; import java.util.Set; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -43,6 +45,7 @@ import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.ServletRequestBindingException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.context.request.WebRequest; import org.springframework.web.context.request.async.AsyncRequestTimeoutException; import org.springframework.web.multipart.support.MissingServletRequestPartException; @@ -464,14 +467,23 @@ public abstract class ResponseEntityExceptionHandler { * @param ex the exception * @param headers the headers to be written to the response * @param status the selected response status - * @param request the current request + * @param webRequest the current request * @return a {@code ResponseEntity} instance * @since 4.2.8 */ protected ResponseEntity handleAsyncRequestTimeoutException( - AsyncRequestTimeoutException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { - - return handleExceptionInternal(ex, null, headers, status, request); + AsyncRequestTimeoutException ex, HttpHeaders headers, HttpStatus status, WebRequest webRequest) { + + if (webRequest instanceof ServletWebRequest) { + ServletWebRequest servletRequest = (ServletWebRequest) webRequest; + HttpServletRequest request = servletRequest.getNativeRequest(HttpServletRequest.class); + HttpServletResponse response = servletRequest.getNativeResponse(HttpServletResponse.class); + if (response.isCommitted()) { + logger.error("Async timeout for " + request.getMethod() + " [" + request.getRequestURI() + "]"); + return null; + } + } + return handleExceptionInternal(ex, null, headers, status, webRequest); } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java index f29e99dde0f..c7a41e5ef32 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolver.java @@ -498,7 +498,12 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes protected ModelAndView handleAsyncRequestTimeoutException(AsyncRequestTimeoutException ex, HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { - response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); + if (!response.isCommitted()) { + response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); + } + else if (logger.isErrorEnabled()) { + logger.error("Async timeout for " + request.getMethod() + " [" + request.getRequestURI() + "]"); + } return new ModelAndView(); } @@ -510,6 +515,7 @@ public class DefaultHandlerExceptionResolver extends AbstractHandlerExceptionRes protected void sendServerError(Exception ex, HttpServletRequest request, HttpServletResponse response) throws IOException { + request.setAttribute("javax.servlet.error.exception", ex); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); }