mirror of
https://github.com/spring-projects/spring-framework
synced 2026-06-08 17:33:33 +00:00
Use preset content-type for streaming response
Closes gh-35130
This commit is contained in:
+16
-7
@@ -242,19 +242,22 @@ class ReactiveTypeHandlerTests {
|
||||
|
||||
// Media type from request
|
||||
this.servletRequest.addHeader("Accept", "text/event-stream");
|
||||
testSseResponse(true);
|
||||
testSseResponse(true, null);
|
||||
|
||||
// Media type from "produces" attribute
|
||||
Set<MediaType> types = Collections.singleton(MediaType.TEXT_EVENT_STREAM);
|
||||
this.servletRequest.setAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, types);
|
||||
testSseResponse(true);
|
||||
testSseResponse(true, null);
|
||||
|
||||
// Preset media type // gh-35130
|
||||
testSseResponse(true, MediaType.TEXT_EVENT_STREAM);
|
||||
|
||||
// No media type preferences
|
||||
testSseResponse(false);
|
||||
testSseResponse(false, null);
|
||||
}
|
||||
|
||||
private void testSseResponse(boolean expectSseEmitter) throws Exception {
|
||||
ResponseBodyEmitter emitter = handleValue(Flux.empty(), Flux.class, forClass(String.class));
|
||||
private void testSseResponse(boolean expectSseEmitter, @Nullable MediaType contentType) throws Exception {
|
||||
ResponseBodyEmitter emitter = handleValue(Flux.empty(), Flux.class, forClass(String.class), contentType);
|
||||
Object actual = emitter instanceof SseEmitter;
|
||||
assertThat(actual).isEqualTo(expectSseEmitter);
|
||||
resetRequest();
|
||||
@@ -450,7 +453,7 @@ class ReactiveTypeHandlerTests {
|
||||
|
||||
try {
|
||||
Sinks.Many<String> sink = Sinks.many().unicast().onBackpressureBuffer();
|
||||
ResponseBodyEmitter emitter = handler.handleValue(sink.asFlux(), returnType, mavContainer, this.webRequest);
|
||||
ResponseBodyEmitter emitter = handler.handleValue(sink.asFlux(), returnType, null, mavContainer, this.webRequest);
|
||||
|
||||
ContextEmitterHandler emitterHandler = new ContextEmitterHandler();
|
||||
emitter.initialize(emitterHandler);
|
||||
@@ -497,9 +500,15 @@ class ReactiveTypeHandlerTests {
|
||||
private ResponseBodyEmitter handleValue(Object returnValue, Class<?> asyncType,
|
||||
ResolvableType genericType) throws Exception {
|
||||
|
||||
return handleValue(returnValue, asyncType, genericType, null);
|
||||
}
|
||||
|
||||
private ResponseBodyEmitter handleValue(Object returnValue, Class<?> asyncType,
|
||||
ResolvableType genericType, @Nullable MediaType contentType) throws Exception {
|
||||
|
||||
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
|
||||
MethodParameter returnType = on(TestController.class).resolveReturnType(asyncType, genericType);
|
||||
return this.handler.handleValue(returnValue, returnType, mavContainer, this.webRequest);
|
||||
return this.handler.handleValue(returnValue, returnType, contentType, mavContainer, this.webRequest);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+20
@@ -28,12 +28,14 @@ import io.micrometer.context.ContextSnapshot;
|
||||
import io.micrometer.context.ContextSnapshot.Scope;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Sinks;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
@@ -342,6 +344,21 @@ class ResponseBodyEmitterReturnValueHandlerTests {
|
||||
assertThat(this.response.isCommitted()).isFalse();
|
||||
}
|
||||
|
||||
@Test // gh-35130
|
||||
void responseEntityFluxSseWithPresetContentType() throws Exception {
|
||||
|
||||
ResponseEntity<Publisher<?>> entity =
|
||||
ResponseEntity.ok().contentType(MediaType.TEXT_EVENT_STREAM).body(Flux.just("foo", "bar"));
|
||||
|
||||
MethodParameter type = on(TestController.class).resolveReturnType(ResponseEntity.class, Publisher.class);
|
||||
this.handler.handleReturnValue(entity, type, this.mavContainer, this.webRequest);
|
||||
|
||||
assertThat(this.request.isAsyncStarted()).isTrue();
|
||||
assertThat(this.response.getStatus()).isEqualTo(200);
|
||||
assertThat(this.response.getContentType()).isEqualTo("text/event-stream");
|
||||
assertThat(this.response.getContentAsString()).isEqualTo("data:foo\n\ndata:bar\n\n");
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings({"unused", "ConstantConditions"})
|
||||
private static class TestController {
|
||||
@@ -365,6 +382,9 @@ class ResponseBodyEmitterReturnValueHandlerTests {
|
||||
private ResponseEntity<Flux<String>> h9() { return null; }
|
||||
|
||||
private ResponseEntity<Flux<SimpleBean>> h10() { return null; }
|
||||
|
||||
private ResponseEntity<Publisher<?>> h11() { return null; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user