diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java index 168e2004e11..347ef5028ed 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandler.java @@ -144,7 +144,12 @@ public class ResponseBodyEmitterReturnValueHandler implements HandlerMethodRetur else { emitter = this.reactiveHandler.handleValue(returnValue, returnType, mavContainer, webRequest); if (emitter == null) { - // Not streaming.. + // Not streaming: write headers without committing response.. + outputMessage.getHeaders().forEach((headerName, headerValues) -> { + for (String headerValue : headerValues) { + response.addHeader(headerName, headerValue); + } + }); return; } } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandlerTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandlerTests.java index 79032395752..59cc2b6fc4e 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandlerTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ResponseBodyEmitterReturnValueHandlerTests.java @@ -42,17 +42,10 @@ import org.springframework.web.context.request.async.StandardServletAsyncWebRequ import org.springframework.web.context.request.async.WebAsyncUtils; import org.springframework.web.method.support.ModelAndViewContainer; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.springframework.core.ResolvableType.forClassWithGenerics; -import static org.springframework.web.method.ResolvableMethod.on; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; +import static org.springframework.core.ResolvableType.*; +import static org.springframework.web.method.ResolvableMethod.*; /** * Unit tests for ResponseBodyEmitterReturnValueHandler. @@ -290,6 +283,21 @@ public class ResponseBodyEmitterReturnValueHandlerTests { assertEquals("foobarbaz", this.response.getContentAsString()); } + @Test // SPR-17076 + public void responseEntityFluxWithCustomHeader() throws Exception { + + EmitterProcessor processor = EmitterProcessor.create(); + ResponseEntity> entity = ResponseEntity.ok().header("x-foo", "bar").body(processor); + ResolvableType bodyType = forClassWithGenerics(Flux.class, SimpleBean.class); + MethodParameter type = on(TestController.class).resolveReturnType(ResponseEntity.class, bodyType); + this.handler.handleReturnValue(entity, type, this.mavContainer, this.webRequest); + + assertTrue(this.request.isAsyncStarted()); + assertEquals(200, this.response.getStatus()); + assertEquals("bar", this.response.getHeader("x-foo")); + assertFalse(this.response.isCommitted()); + } + @SuppressWarnings("unused") private static class TestController { @@ -312,6 +320,7 @@ public class ResponseBodyEmitterReturnValueHandlerTests { private ResponseEntity> h9() { return null; } + private ResponseEntity> h10() { return null; } }