spring-cloud-gateway icon indicating copy to clipboard operation
spring-cloud-gateway copied to clipboard

Support Websockets in gateway server webmvc

Open eljefe6a opened this issue 1 year ago • 8 comments

I'm trying to get the secure websocket or non-secure websockets to work with the gateway in version 4.1.4. I get the same error using wss or ws.

I'm getting this error on startup:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'routerFunctionMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Error creating bean with name 'gatewayCompositeRouterFunction': Error creating bean with name 'scopedTarget.gatewayRouterFunctionHolder': Failed to instantiate [org.springframework.cloud.gateway.server.mvc.config.GatewayMvcPropertiesBeanDefinitionRegistrar$RouterFunctionHolder]: Factory method 'routerFunctionHolderSupplier' threw exception with message: Unable to find HandlerFunction for scheme: wss
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1788) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:962) ~[spring-context-6.1.8.jar:6.1.8]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:624) ~[spring-context-6.1.8.jar:6.1.8]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.3.0.jar:3.3.0]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.3.0.jar:3.3.0]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.3.0.jar:3.3.0]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.3.0.jar:3.3.0]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.0.jar:3.3.0]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.0.jar:3.3.0]
        at com.alphabet.webservices.WebservicesApplication.main(WebservicesApplication.java:25) ~[classes/:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
        at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) ~[spring-boot-devtools-3.3.0.jar:3.3.0]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'gatewayCompositeRouterFunction': Error creating bean with name 'scopedTarget.gatewayRouterFunctionHolder': Failed to instantiate [org.springframework.cloud.gateway.server.mvc.config.GatewayMvcPropertiesBeanDefinitionRegistrar$RouterFunctionHolder]: Factory method 'routerFunctionHolderSupplier' threw exception with message: Unable to find HandlerFunction for scheme: wss
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:607) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory$1.orderedStream(DefaultListableBeanFactory.java:473) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.web.servlet.function.support.RouterFunctionMapping.initRouterFunctions(RouterFunctionMapping.java:152) ~[spring-webmvc-6.1.8.jar:6.1.8]
        at org.springframework.web.servlet.function.support.RouterFunctionMapping.afterPropertiesSet(RouterFunctionMapping.java:130) ~[spring-webmvc-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1835) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1784) ~[spring-beans-6.1.8.jar:6.1.8]
        ... 21 common frames omitted
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.gatewayRouterFunctionHolder': Failed to instantiate [org.springframework.cloud.gateway.server.mvc.config.GatewayMvcPropertiesBeanDefinitionRegistrar$RouterFunctionHolder]: Factory method 'routerFunctionHolderSupplier' threw exception with message: Unable to find HandlerFunction for scheme: wss
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:648) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:485) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1337) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1167) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$1(AbstractBeanFactory.java:376) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.cloud.context.scope.GenericScope$BeanLifecycleWrapper.getBean(GenericScope.java:375) ~[spring-cloud-context-4.1.3.jar:4.1.3]
        at org.springframework.cloud.context.scope.GenericScope.get(GenericScope.java:179) ~[spring-cloud-context-4.1.3.jar:4.1.3]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:373) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35) ~[spring-aop-6.1.8.jar:6.1.8]
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:704) ~[spring-aop-6.1.8.jar:6.1.8]
        at org.springframework.cloud.gateway.server.mvc.config.GatewayMvcPropertiesBeanDefinitionRegistrar$RouterFunctionHolder$$SpringCGLIB$$0.getRouterFunction(<generated>) ~[spring-cloud-gateway-server-mvc-4.1.4.jar:na]
        at org.springframework.cloud.gateway.server.mvc.config.GatewayMvcPropertiesBeanDefinitionRegistrar$DelegatingRouterFunction.accept(GatewayMvcPropertiesBeanDefinitionRegistrar.java:140) ~[spring-cloud-gateway-server-mvc-4.1.4.jar:4.1.4]
        at org.springframework.cloud.gateway.server.mvc.common.ArgumentSupplierBeanPostProcessor.postProcessBeforeInitialization(ArgumentSupplierBeanPostProcessor.java:52) ~[spring-cloud-gateway-server-mvc-4.1.4.jar:4.1.4]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:422) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1780) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) ~[spring-beans-6.1.8.jar:6.1.8]
        ... 31 common frames omitted
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.cloud.gateway.server.mvc.config.GatewayMvcPropertiesBeanDefinitionRegistrar$RouterFunctionHolder]: Factory method 'routerFunctionHolderSupplier' threw exception with message: Unable to find HandlerFunction for scheme: wss
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:177) ~[spring-beans-6.1.8.jar:6.1.8]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:644) ~[spring-beans-6.1.8.jar:6.1.8]
        ... 49 common frames omitted
Caused by: java.lang.IllegalStateException: Unable to find HandlerFunction for scheme: wss
        at org.springframework.cloud.gateway.server.mvc.config.RouterFunctionHolderFactory.getRouterFunction(RouterFunctionHolderFactory.java:172) ~[spring-cloud-gateway-server-mvc-4.1.4.jar:4.1.4]
        at org.springframework.cloud.gateway.server.mvc.config.RouterFunctionHolderFactory.lambda$routerFunctionHolderSupplier$1(RouterFunctionHolderFactory.java:119) ~[spring-cloud-gateway-server-mvc-4.1.4.jar:4.1.4]
        at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) ~[na:na]
        at org.springframework.cloud.gateway.server.mvc.config.RouterFunctionHolderFactory.routerFunctionHolderSupplier(RouterFunctionHolderFactory.java:118) ~[spring-cloud-gateway-server-mvc-4.1.4.jar:4.1.4]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) ~[spring-beans-6.1.8.jar:6.1.8]
        ... 50 common frames omitted

This is my application.yml:

  cloud:
    gateway:
      mvc:
        routes:
        - id: websocket
          uri: wss://example.com:9443
          predicates:
            - Path=/example/**

Here is the dependency:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway-mvc</artifactId>
            <version>4.1.4</version>
        </dependency>

Is there something misconfigured?

eljefe6a avatar Jun 28 '24 13:06 eljefe6a

Yes, websockets are not supported yet in MVC gateway

spencergibb avatar Jun 28 '24 15:06 spencergibb

So they're supported in the spring-cloud-starter-gateway?

eljefe6a avatar Jun 30 '24 12:06 eljefe6a

Yes the reactive version has websocket support.

I just spent a few days migrating our gateway from reactive to mvc (because I need some Tomcat features), just to find out that websockets arent supported. This renders it useless for us...

Would be good to have an comparing overview of the two approaches in the documentation.

HSKC avatar Jul 25 '24 07:07 HSKC

It is a planned feature

spencergibb avatar Jul 25 '24 13:07 spencergibb

I agree with @HSKC. I lost several days because this isn't clearly documented. This thread is the only documentation that it doesn't work. I'd love to see something more explicit in the readme.

eljefe6a avatar Jul 25 '24 13:07 eljefe6a

Does anyone already know why it is not supported yet? I maybe need that feature. I have already several workarounds in place so I could add another one here in my implementation, if I know where to start. :)

jensmatw avatar Sep 11 '24 12:09 jensmatw

Is they any eta of this feature ? I would be very nice !

dutrieux avatar Feb 12 '25 22:02 dutrieux

Will this feature gain some traction someday on Spring Cloud MVC? I'm on a special situation, we migrated from reactive to mvc, but the lack of websockets on mvc left us with 2 simultaneous api gateways, one for the websockets (reactive) and the other (mvc) for everything else, which is no ideal.

martinrevert avatar Mar 11 '25 20:03 martinrevert