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

Proxy websocket wss:// to ws:// spring cloud gateway

Open intumba opened this issue 4 years ago • 3 comments

500 Server Error for HTTP GET "/stomp" I have an instance of Unsecured ActiveMQ-5.16.0 and I want to route secured websocket to ActiveMQ using Spring Cloud Gateway. I have tried the solution using the documentation from Spring Cloud and I get the following issue:

500 Server Error for HTTP GET "/stomp".

Any idea why I am getting java.lang.ClassCastException

Route builder config code snippet

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class BeanConfig {

    @Bean
    public RouteLocator gatewayRoutes(RouteLocatorBuilder builder) {
        return builder.routes()
                .route(r -> r.path("/stomp/**")
                        .filters(f -> f
                                .rewritePath("/stomp/?(?<segment>.*)", "/$\\{segment}")
                                .addRequestHeader("Sec-WebSocket-Protocol", "v10.stomp, v11.stomp")
                        )
                        .uri("ws://localhost:61614"))
                .build();
    }
}

Stacktrace:

2021-11-03 07:08:27.245 ERROR 5200 --- [io-8443-exec-10] a.w.r.e.AbstractErrorWebExceptionHandler : [d9a04a]  500 Server Error for HTTP GET "/stomp"

java.lang.ClassCastException: org.apache.catalina.connector.ResponseFacade cannot be cast to reactor.netty.http.server.HttpServerResponse
        at org.springframework.web.reactive.socket.server.upgrade.ReactorNettyRequestUpgradeStrategy.getNativeResponse(ReactorNettyRequestUpgradeStrategy.java:93) ~[spring-webflux-5.2.3.RELEASE.jar:5.2.3.RELEASE]
        Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
        |_ checkpoint ? org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.web.server.authorization.AuthorizationWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.web.server.authentication.logout.LogoutWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.web.server.savedrequest.ServerRequestCacheWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.web.server.ui.LogoutPageGeneratingWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.web.server.ui.LoginPageGeneratingWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.web.server.authentication.AuthenticationWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.web.server.authentication.AuthenticationWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.web.server.context.ReactorContextWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.web.server.csrf.CsrfWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.web.server.header.HttpHeaderWriterWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
        |_ checkpoint ? org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
        |_ checkpoint ? HTTP GET "/stomp" [ExceptionHandlingWebHandler]
Stack trace:
                at org.springframework.web.reactive.socket.server.upgrade.ReactorNettyRequestUpgradeStrategy.getNativeResponse(ReactorNettyRequestUpgradeStrategy.java:93) ~[spring-webflux-5.2.3.RELEASE.jar:5.2.3.RELEASE]
                at org.springframework.web.reactive.socket.server.upgrade.ReactorNettyRequestUpgradeStrategy.upgrade(ReactorNettyRequestUpgradeStrategy.java:77) ~[spring-webflux-5.2.3.RELEASE.jar:5.2.3.RELEASE]
                at org.springframework.web.reactive.socket.server.support.HandshakeWebSocketService.lambda$handleRequest$1(HandshakeWebSocketService.java:235) ~[spring-webflux-5.2.3.RELEASE.jar:5.2.3.RELEASE]
                at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:151) ~[reactor-core-3.3.2.RELEASE.jar:3.3.2.RELEASE]
                at reactor.core.publisher.MonoFlatMap.subscribeOrReturn(MonoFlatMap.java:53) ~[reactor-core-3.3.2.RELEASE.jar:3.3.2.RELEASE]
                at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:48) ~[reactor-core-3.3.2.RELEASE.jar:3.3.2.RELEASE]
                at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.3.2.RELEASE.jar:3.3.2.RELEASE]
                at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.3.2.RELEASE.jar:3.3.2.RELEASE]
                at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.3.2.RELEASE.jar:3.3.2.RELEASE]
                at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.3.2.RELEASE.jar:3.3.2.RELEASE]
                at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.3.2.RELEASE.jar:3.3.2.RELEASE]

intumba avatar Nov 03 '21 07:11 intumba

Can you describe your setup more? Where does org.apache.catalina.connector.ResponseFacade come from?

spencergibb avatar Nov 05 '21 21:11 spencergibb

@spencergibb the org.apache.catalina.connector.ResponseFacade is coming from Active MQ 5.16.0 and I tried even using a simple java websocket server custom app, the outcome is the same.

I am using Active MQ 5.16.0 standalone server for my web socket [ws://localhost:61614/stomp/queue/test]. I used the sample provided by Active MQ stomp example.

I use spring-cloud-gateway to proxy the unsecured Active MQ standalone behind the secured gateway. I then route the wss:// to ws:// using spring cloud.

I have a simple HTTPS client running on https://localhost:8443/index.html which try to connect to Active MQ ws://localhost:61614/stomp/queue/test through the proxy at wss://localhost:8443/

I have created a repo of this sample code: https://github.com/intumba/spring-cloud-gateway and I got this sample code from the github repos.

Hope this describes my use case.

intumba avatar Nov 07 '21 07:11 intumba

I am facing the exact same issue.

yj-cactus avatar Jun 07 '22 10:06 yj-cactus

Sorry for the late reply. If this still happens with Spring Boot 3.2 and Cloud 2023.0 we can reopen and assess.

spencergibb avatar Mar 14 '24 01:03 spencergibb