Skip to content

ClassCastException when use ServerHttpResponseDecorator to modify response of websocket #23598

Closed
@SaigonoHanabi

Description

@SaigonoHanabi

Execuse me, I really need your help!
I submit an issue in spring-cloud-gateway project, but their member let me reach out to you.

In gateway, I want to modify response and return some customized message to client when websocket connect success. Then I add a filter and copy codes from ModifyResponseBodyGatewayFilterFactory.
My spring cloud version is Greenwich.SR2. But finally I got a ClassCastException.
Is there any way to solve this exception?

Here is the exception :

2019-09-06 10:14:49.199 ERROR 17200 --- [ctor-http-nio-8] a.w.r.e.AbstractErrorWebExceptionHandler : [551d2e4c] 500 Server Error for HTTP GET "/websocket"

java.lang.ClassCastException: com.test.demo.gateway.filters.ModifyResponseFilter$1 cannot be cast to org.springframework.http.server.reactive.AbstractServerHttpResponse
	at org.springframework.web.reactive.socket.server.upgrade.ReactorNettyRequestUpgradeStrategy.upgrade(ReactorNettyRequestUpgradeStrategy.java:75) ~[spring-webflux-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.web.reactive.socket.server.support.HandshakeWebSocketService.lambda$handleRequest$1(HandshakeWebSocketService.java:235) ~[spring-webflux-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at reactor.core.publisher.FluxFlatMap.trySubscribeScalarMap(FluxFlatMap.java:141) [reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:53) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoPeek.subscribe(MonoPeek.java:71) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.Mono.subscribe(Mono.java:3852) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:172) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:74) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoDoFinally.subscribe(MonoDoFinally.java:47) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.Mono.subscribe(Mono.java:3852) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:172) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:76) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerNext(FluxConcatMap.java:275) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:849) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:114) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:144) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:114) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:76) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerNext(FluxConcatMap.java:275) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:849) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:73) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:192) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoFilterWhen$MonoFilterWhenMain.onNext(MonoFilterWhen.java:140) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2071) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoFilterWhen$MonoFilterWhenMain.onSubscribe(MonoFilterWhen.java:103) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:54) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoFilterWhen.subscribe(MonoFilterWhen.java:56) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoPeek.subscribe(MonoPeek.java:71) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.Mono.subscribe(Mono.java:3852) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:442) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onNext(FluxConcatMap.java:244) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxDematerialize$DematerializeSubscriber.onNext(FluxDematerialize.java:114) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxDematerialize$DematerializeSubscriber.onNext(FluxDematerialize.java:42) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drainAsync(FluxFlattenIterable.java:395) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drain(FluxFlattenIterable.java:638) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.onNext(FluxFlattenIterable.java:242) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:179) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1498) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.DrainUtils.postCompleteDrain(DrainUtils.java:131) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.DrainUtils.postComplete(DrainUtils.java:186) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxMaterialize$MaterializeSubscriber.onComplete(FluxMaterialize.java:134) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drainAsync(FluxFlattenIterable.java:325) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drain(FluxFlattenIterable.java:638) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.onComplete(FluxFlattenIterable.java:259) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:144) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1499) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:794) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:560) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxFlatMap$FlatMapMain.drain(FluxFlatMap.java:540) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxFlatMap$FlatMapMain.onComplete(FluxFlatMap.java:426) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:265) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:201) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxFlatMap$FlatMapMain.onSubscribe(FluxFlatMap.java:335) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:139) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:63) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxFlatMap.subscribe(FluxFlatMap.java:97) [reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoCollectList.subscribe(MonoCollectList.java:40) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoMapFuseable.subscribe(MonoMapFuseable.java:59) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoFlattenIterable.subscribe(MonoFlattenIterable.java:101) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxMaterialize.subscribe(FluxMaterialize.java:40) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoCollectList.subscribe(MonoCollectList.java:40) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:74) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoFlattenIterable.subscribe(MonoFlattenIterable.java:101) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxDematerialize.subscribe(FluxDematerialize.java:39) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:54) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxConcatMap.subscribe(FluxConcatMap.java:121) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoNext.subscribe(MonoNext.java:40) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoMap.subscribe(MonoMap.java:55) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoSwitchIfEmpty.subscribe(MonoSwitchIfEmpty.java:44) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoMap.subscribe(MonoMap.java:55) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.Mono.subscribe(Mono.java:3852) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:442) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:212) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:139) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:63) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.FluxConcatMap.subscribe(FluxConcatMap.java:121) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoNext.subscribe(MonoNext.java:40) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoSwitchIfEmpty.subscribe(MonoSwitchIfEmpty.java:44) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoPeekTerminal.subscribe(MonoPeekTerminal.java:61) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.Mono.subscribe(Mono.java:3852) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:172) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:70) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.core.publisher.MonoPeekTerminal.subscribe(MonoPeekTerminal.java:61) ~[reactor-core-3.2.11.RELEASE.jar:3.2.11.RELEASE]
	at reactor.netty.http.server.HttpServerHandle.onStateChange(HttpServerHandle.java:64) ~[reactor-netty-0.8.10.RELEASE.jar:0.8.10.RELEASE]
	at reactor.netty.tcp.TcpServerBind$ChildObserver.onStateChange(TcpServerBind.java:226) ~[reactor-netty-0.8.10.RELEASE.jar:0.8.10.RELEASE]
	at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:442) ~[reactor-netty-0.8.10.RELEASE.jar:0.8.10.RELEASE]
	at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:91) ~[reactor-netty-0.8.10.RELEASE.jar:0.8.10.RELEASE]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:161) ~[reactor-netty-0.8.10.RELEASE.jar:0.8.10.RELEASE]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:328) ~[netty-codec-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:302) ~[netty-codec-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1421) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:697) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:632) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:549) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:511) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:918) ~[netty-common-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.38.Final.jar:4.1.38.Final]
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.38.Final.jar:4.1.38.Final]
	at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_144]

Here is my filter :

public class ModifyResponseFilter implements GatewayFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        System.out.println("pass ModifyResponseFilter...");
        return chain.filter(exchange.mutate().response(decorate(exchange)).build());
    }

    @Override
    public int getOrder() {
        return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
    }

    ServerHttpResponse decorate(ServerWebExchange exchange) {
        return new ServerHttpResponseDecorator(exchange.getResponse()) {

            @Override
            public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {

                Class inClass = String.class;
                Class outClass = String.class;

                String originalResponseContentType = exchange
                        .getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
                HttpHeaders httpHeaders = new HttpHeaders();
                // explicitly add it in this way instead of
                // 'httpHeaders.setContentType(originalResponseContentType)'
                // this will prevent exception in case of using non-standard media
                // types like "Content-Type: image"
                httpHeaders.add(HttpHeaders.CONTENT_TYPE,
                        originalResponseContentType);

                ClientResponse clientResponse = ClientResponse
                        .create(exchange.getResponse().getStatusCode())
                        .headers(headers -> headers.putAll(httpHeaders))
                        .body(Flux.from(body)).build();

                // TODO: flux or mono
                Mono modifiedBody = clientResponse.bodyToMono(inClass)
                        .flatMap(originalBody -> {
                            String newResult =  "modify response : " + originalBody;
                            return Mono.just(newResult);
                        });

                BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, outClass);
                CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(
                        exchange, exchange.getResponse().getHeaders());
                return bodyInserter.insert(outputMessage, new BodyInserterContext())
                        .then(Mono.defer(() -> {
                            Flux<DataBuffer> messageBody = outputMessage.getBody();
                            HttpHeaders headers = getDelegate().getHeaders();
                            if (!headers.containsKey(HttpHeaders.TRANSFER_ENCODING)) {
                                messageBody = messageBody.doOnNext(data -> headers
                                        .setContentLength(data.readableByteCount()));
                            }
                            // TODO: fail if isStreamingMediaType?
                            return getDelegate().writeWith(messageBody);
                        }));
            }

            @Override
            public Mono<Void> writeAndFlushWith(
                    Publisher<? extends Publisher<? extends DataBuffer>> body) {
                return writeWith(Flux.from(body).flatMapSequential(p -> p));
            }
        };
    }
}

In ReactorNettyRequestUpgradeStrategy, I found a force cast from exchange.getResponse() to AbstractServerHttpResponse, so the ServerHttpResponseDecorator is failed.

public class ReactorNettyRequestUpgradeStrategy implements RequestUpgradeStrategy {
    private int maxFramePayloadLength = 65536;

    public ReactorNettyRequestUpgradeStrategy() {
    }

    public void setMaxFramePayloadLength(Integer maxFramePayloadLength) {
        this.maxFramePayloadLength = maxFramePayloadLength;
    }

    public int getMaxFramePayloadLength() {
        return this.maxFramePayloadLength;
    }

    public Mono<Void> upgrade(ServerWebExchange exchange, WebSocketHandler handler, @Nullable String subProtocol, Supplier<HandshakeInfo> handshakeInfoFactory) {
        ServerHttpResponse response = exchange.getResponse();
        HttpServerResponse reactorResponse = (HttpServerResponse)((AbstractServerHttpResponse)response).getNativeResponse();
        HandshakeInfo handshakeInfo = (HandshakeInfo)handshakeInfoFactory.get();
        NettyDataBufferFactory bufferFactory = (NettyDataBufferFactory)response.bufferFactory();
        return reactorResponse.sendWebsocket(subProtocol, this.maxFramePayloadLength, (in, out) -> {
            ReactorNettyWebSocketSession session = new ReactorNettyWebSocketSession(in, out, handshakeInfo, bufferFactory, this.maxFramePayloadLength);
            return handler.handle(session);
        });
    }
}

spring-cloud-gateway-websocket-demo.zip

You can reproduce the exception with this demo.

  1. start EurekaApplication
  2. start GatewayApplication
  3. start WebSocketServerApplication
  4. run com.test.demo.websocketserver.WebSocketClient.java in websocket-server project

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions