Fix GraphQL WebSocket HandlerMapping bean ordering

Prior to this commit, the GraphQL WebSocket HandlerMapping bean would be
ordered at position "2", before the RouterFunction variant defined by
Spring Framework at position "3".

Since then, the Spring Framework team changed the default order value
for this one at "-1", see spring-projects/spring-framework#30278.
This prevents the WebSocket upgrade, as the request is handled by the
RouterFunction instead of the WebSocket handler.

This commit updates the handlermapping order and introduces a test to
prevent issues in the future.

Fixes gh-37892
This commit is contained in:
Brian Clozel 2023-10-16 12:11:31 +02:00
parent 4c3a0f09d7
commit 339f75d309
2 changed files with 11 additions and 3 deletions

View File

@ -195,7 +195,7 @@ public class GraphQlWebMvcAutoConfiguration {
mapping.setWebSocketUpgradeMatch(true);
mapping.setUrlMap(Collections.singletonMap(path,
handler.initWebSocketHttpRequestHandler(new DefaultHandshakeHandler())));
mapping.setOrder(2); // Ahead of HTTP endpoint ("routerFunctionMapping" bean)
mapping.setOrder(-2); // Ahead of HTTP endpoint ("routerFunctionMapping" bean)
return mapping;
}

View File

@ -45,7 +45,11 @@ import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.support.RouterFunctionMapping;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.socket.server.support.WebSocketHandlerMapping;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.asyncDispatch;
@ -162,8 +166,12 @@ class GraphQlWebMvcAutoConfigurationTests {
@Test
void shouldConfigureWebSocketBeans() {
this.contextRunner.withPropertyValues("spring.graphql.websocket.path=/ws")
.run((context) -> assertThat(context).hasSingleBean(GraphQlWebSocketHandler.class));
this.contextRunner.withPropertyValues("spring.graphql.websocket.path=/ws").run((context) -> {
assertThat(context).hasSingleBean(GraphQlWebSocketHandler.class);
assertThat(context.getBeanProvider(HandlerMapping.class).orderedStream().toList()).containsSubsequence(
context.getBean(WebSocketHandlerMapping.class), context.getBean(RouterFunctionMapping.class),
context.getBean(RequestMappingHandlerMapping.class));
});
}
@Test