diff --git a/spring-web/src/main/java/org/springframework/web/util/DisconnectedClientHelper.java b/spring-web/src/main/java/org/springframework/web/util/DisconnectedClientHelper.java index b2b16f135adb..d1c47b192c67 100644 --- a/spring-web/src/main/java/org/springframework/web/util/DisconnectedClientHelper.java +++ b/spring-web/src/main/java/org/springframework/web/util/DisconnectedClientHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import org.springframework.core.NestedExceptionUtils; import org.springframework.util.Assert; +import org.springframework.web.client.RestClientException; /** * Utility methods to assist with identifying and logging exceptions that indicate @@ -32,6 +33,7 @@ * and a full stacktrace at TRACE level. * * @author Rossen Stoyanchev + * @author Yanming Zhou * @since 6.1 */ public class DisconnectedClientHelper { @@ -83,6 +85,13 @@ else if (logger.isDebugEnabled()) { * */ public static boolean isClientDisconnectedException(Throwable ex) { + Throwable cause = ex; + while (cause != null) { + if (cause instanceof RestClientException) { + return false; + } + cause = cause.getCause(); + } String message = NestedExceptionUtils.getMostSpecificCause(ex).getMessage(); if (message != null) { String text = message.toLowerCase(Locale.ROOT); 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 f44a3eb4a2fa..372fe9f0c0bb 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -51,7 +51,6 @@ import org.springframework.web.servlet.NoHandlerFoundException; import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver; import org.springframework.web.servlet.resource.NoResourceFoundException; -import org.springframework.web.util.DisconnectedClientHelper; import org.springframework.web.util.WebUtils; /** @@ -149,6 +148,7 @@ * @author Arjen Poutsma * @author Rossen Stoyanchev * @author Juergen Hoeller + * @author Yanming Zhou * @since 3.0 * @see org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler */ @@ -246,9 +246,6 @@ else if (ex instanceof AsyncRequestNotUsableException) { return handleAsyncRequestNotUsableException( (AsyncRequestNotUsableException) ex, request, response, handler); } - else if (DisconnectedClientHelper.isClientDisconnectedException(ex)) { - return handleDisconnectedClientException(ex, request, response, handler); - } } catch (Exception handlerEx) { if (logger.isWarnEnabled()) { @@ -505,26 +502,6 @@ protected ModelAndView handleAsyncRequestNotUsableException(AsyncRequestNotUsabl return new ModelAndView(); } - /** - * Handle an Exception that indicates the client has gone away. This is - * typically an {@link IOException} of a specific subtype or with a message - * specific to the underlying Servlet container. Those are detected through - * {@link DisconnectedClientHelper#isClientDisconnectedException(Throwable)} - *
By default, do nothing since the response is not usable. - * @param ex the {@code Exception} to be handled - * @param request current HTTP request - * @param response current HTTP response - * @param handler the executed handler, or {@code null} if none chosen - * at the time of the exception (for example, if multipart resolution failed) - * @return an empty ModelAndView indicating the exception was handled - * @since 6.2 - */ - protected ModelAndView handleDisconnectedClientException( - Exception ex, HttpServletRequest request, HttpServletResponse response, @Nullable Object handler) { - - return new ModelAndView(); - } - /** * Handle an {@link ErrorResponse} exception. *
The default implementation sets status and the headers of the response diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java index a81ac3f97dc5..eb95f0ab2e84 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/support/DefaultHandlerExceptionResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.web.servlet.mvc.support; import java.lang.reflect.Method; +import java.net.SocketException; import java.util.Arrays; import java.util.Collections; @@ -42,6 +43,7 @@ import org.springframework.web.bind.MissingPathVariableException; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.ServletRequestBindingException; +import org.springframework.web.client.RestClientException; import org.springframework.web.context.request.async.AsyncRequestTimeoutException; import org.springframework.web.multipart.MaxUploadSizeExceededException; import org.springframework.web.multipart.support.MissingServletRequestPartException; @@ -60,6 +62,7 @@ * * @author Arjen Poutsma * @author Sebastien Deleuze + * @author Yanming Zhou */ class DefaultHandlerExceptionResolverTests { @@ -248,6 +251,17 @@ void handleMaxUploadSizeExceededException() { assertThat(response.getErrorMessage()).isEqualTo("Maximum upload size exceeded"); } + @Test + void handleRestClientExceptionHasConnectionResetMessage() { + RestClientException ex = new RestClientException("I/O error", new SocketException("Connection reset")); + ModelAndView mav = exceptionResolver.resolveException(request, response, null, ex); + assertThat(mav).as("ModelAndView is returned").isNull(); + + Exception exception = new Exception(ex.getMessage(), ex); + mav = exceptionResolver.resolveException(request, response, null, exception); + assertThat(mav).as("ModelAndView is returned").isNull(); + } + @Test void customModelAndView() { ModelAndView expected = new ModelAndView();