Skip to content

Content-Type response header duplicated for failed StreamingResponseBody return value #34366

Open
@rendstrasser

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 ...

... is called multiple times for two different 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:

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();
    }
}

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)status: feedback-providedFeedback has been providedstatus: waiting-for-triageAn issue we've not yet triaged or decided on

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions