Closed
Description
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.
- start EurekaApplication
- start GatewayApplication
- start WebSocketServerApplication
- run com.test.demo.websocketserver.WebSocketClient.java in websocket-server project