diff --git a/spring-web/src/main/java/org/springframework/web/bind/annotation/ResponseStatus.java b/spring-web/src/main/java/org/springframework/web/bind/annotation/ResponseStatus.java index 1983f5124fa..7dd79d50704 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/annotation/ResponseStatus.java +++ b/spring-web/src/main/java/org/springframework/web/bind/annotation/ResponseStatus.java @@ -30,11 +30,23 @@ import org.springframework.http.HttpStatus; * {@link #reason} that should be returned. * *
The status code is applied to the HTTP response when the handler - * method is invoked, or whenever said exception is thrown. + * method is invoked. + * + *
Note: when using this annotation on an exception class, + * or when setting the {@code reason} attribute of the annotation, + * the {@code HttpServletResponse.sendError} method will be used. + * + * With {@code HttpServletResponse.sendError}, the response is considered + * complete and should not be written to any further. + * Furthermore servlet container will typically write an HTML error page + * therefore making the use of a reason unsuitable for REST APIs. + * For such cases prefer the use of {@link org.springframework.http.ResponseEntity} + * as a return type and avoid {@code ResponseStatus} altogether. * * @author Arjen Poutsma * @author Sam Brannen * @see org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver + * @see javax.servlet.http.HttpServletResponse#sendError(int, String) * @since 3.0 */ @Target({ElementType.TYPE, ElementType.METHOD}) @@ -54,18 +66,13 @@ public @interface ResponseStatus { * typically be changed to something more appropriate. * @since 4.2 * @see javax.servlet.http.HttpServletResponse#setStatus(int) + * @see javax.servlet.http.HttpServletResponse#sendError(int) */ @AliasFor("value") HttpStatus code() default HttpStatus.INTERNAL_SERVER_ERROR; /** * The reason to be used for the response. - *
Note: due to the use of - * {@code HttpServletResponse.sendError(int, String)}, the response will be - * considered complete and should not be written to any further. Furthermore - * servlet container will typically write an HTML error page therefore making - * the use of a reason unsuitable for REST APIs. For such cases prefer - * sending error details in the body of the response. * @see javax.servlet.http.HttpServletResponse#sendError(int, String) */ String reason() default ""; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/ResponseStatusExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/ResponseStatusExceptionResolver.java index 81e6999caf7..7bf45276602 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/ResponseStatusExceptionResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/annotation/ResponseStatusExceptionResolver.java @@ -100,7 +100,7 @@ public class ResponseStatusExceptionResolver extends AbstractHandlerExceptionRes reason = this.messageSource.getMessage(reason, null, reason, LocaleContextHolder.getLocale()); } if (!StringUtils.hasLength(reason)) { - response.setStatus(statusCode); + response.sendError(statusCode); } else { response.sendError(statusCode, reason); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/annotation/ResponseStatusExceptionResolverTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/annotation/ResponseStatusExceptionResolverTests.java index 8b99f7732fe..4df11749174 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/annotation/ResponseStatusExceptionResolverTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/annotation/ResponseStatusExceptionResolverTests.java @@ -57,6 +57,7 @@ public class ResponseStatusExceptionResolverTests { assertNotNull("No ModelAndView returned", mav); assertTrue("No Empty ModelAndView returned", mav.isEmpty()); assertEquals("Invalid status code", 400, response.getStatus()); + assertTrue("Response has not been committed", response.isCommitted()); } @Test @@ -67,6 +68,7 @@ public class ResponseStatusExceptionResolverTests { assertTrue("No Empty ModelAndView returned", mav.isEmpty()); assertEquals("Invalid status code", 410, response.getStatus()); assertEquals("Invalid status reason", "You suck!", response.getErrorMessage()); + assertTrue("Response has not been committed", response.isCommitted()); } @Test