Open
Description
Spring Boot: 3.4.2
Spring Framework: 6.2.2
When setting ResponseEntity#contentType
- in the GET mapping return value of a REST controller,
- and the result of the exception handler, ...
... then the Content-Type
header is duplicated on the response for a request that fails within StreamingResponseBody#writeTo
:
HTTP/1.1 500 Server Error
Date: Tue, 04 Feb 2025 18:29:32 GMT
Vary: Accept-Encoding
Content-Type: application/json
Content-Type: application/json
Content-Length: 0
This might be specific to async requests, like when using StreamingResponseBody
.
When debugging locally, I found that ...
ServletServerHttpResponse
objects that hold the same HttpServletResponse
. This might be expected, because different ServletServerHttpResponse
objects can hold different header values. However, this leads to the content type being duplicated.
The two ServletServerHttpResponse
are created at:
- through
Removing the content type at either of the places has a downside:
- GET mapping: There is no content-type set in the successful case
- Exception handler: There is no content-type set in the exception case for other APIs which are not async.
Is the duplication of content-type expected here?
Please let me know if more info is required. Thank you in advance, any help is appreciated!
Reproducer:
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
@RestController
@RequestMapping("stream")
@ControllerAdvice
public class StreamingRestApi {
@GetMapping(produces = "application/json")
public ResponseEntity<StreamingResponseBody> task() {
StreamingResponseBody streamingResponseBody = outputStream -> {
if (true) {
throw new RuntimeException();
}
};
return ResponseEntity.ok()
.contentType(MediaType.APPLICATION_JSON)
.body(streamingResponseBody);
}
@ExceptionHandler
public ResponseEntity<StreamingResponseBody> handleException(Exception exception) {
return ResponseEntity.internalServerError()
.contentType(MediaType.APPLICATION_JSON)
.build();
}
}