Skip to content

Commit cc154bb

Browse files
committed
Avoid 406 Not Acceptable for error pages
Prior to this commit, the `ErrorController` would override the original error response status if the error map cannot be written due to content negotiation with the HTTP client. In that case, the error handling infrastructure returns a `406 Not Acceptable` response. This commit improves the `ErrorController` so that `HttpMediaTypeNotAcceptableException` instances thrown by that controller are not returned as is but instead we write the error response with an empty body and the original HTTP error status. Fixes gh-19522
1 parent c2f8741 commit cc154bb

File tree

2 files changed

+24
-0
lines changed

2 files changed

+24
-0
lines changed

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorController.java

+8
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
import org.springframework.http.ResponseEntity;
3333
import org.springframework.stereotype.Controller;
3434
import org.springframework.util.Assert;
35+
import org.springframework.web.HttpMediaTypeNotAcceptableException;
36+
import org.springframework.web.bind.annotation.ExceptionHandler;
3537
import org.springframework.web.bind.annotation.RequestMapping;
3638
import org.springframework.web.servlet.ModelAndView;
3739

@@ -102,6 +104,12 @@ public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
102104
return new ResponseEntity<>(body, status);
103105
}
104106

107+
@ExceptionHandler(HttpMediaTypeNotAcceptableException.class)
108+
public ResponseEntity<String> mediaTypeNotAcceptable(HttpServletRequest request) {
109+
HttpStatus status = getStatus(request);
110+
return ResponseEntity.status(status).build();
111+
}
112+
105113
/**
106114
* Determine if the stacktrace attribute should be included.
107115
* @param request the source request

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/servlet/error/BasicErrorControllerIntegrationTests.java

+16
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,17 @@ void testConventionTemplateMapping() {
200200
assertThat(resp).contains("We are out of storage");
201201
}
202202

203+
@Test
204+
void testIncompatibleMediaType() {
205+
load();
206+
RequestEntity<?> request = RequestEntity.get(URI.create(createUrl("/incompatibleType")))
207+
.accept(MediaType.TEXT_PLAIN).build();
208+
ResponseEntity<String> entity = new TestRestTemplate().exchange(request, String.class);
209+
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.BAD_REQUEST);
210+
assertThat(entity.getHeaders().getContentType()).isNull();
211+
assertThat(entity.getBody()).isNull();
212+
}
213+
203214
private void assertErrorAttributes(Map<?, ?> content, String status, String error, Class<?> exception,
204215
String message, String path) {
205216
assertThat(content.get("status")).as("Wrong status").isEqualTo(status);
@@ -298,6 +309,11 @@ String noStorage() {
298309
throw new InsufficientStorageException();
299310
}
300311

312+
@RequestMapping(path = "/incompatibleType", produces = "text/plain")
313+
String incompatibleType() {
314+
throw new ExpectedException();
315+
}
316+
301317
@ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "Expected!")
302318
@SuppressWarnings("serial")
303319
static class ExpectedException extends RuntimeException {

0 commit comments

Comments
 (0)