I'm putting a Spring Cloud Gateway in front of some existing microservices. It mostly works, but I have a websocket (SockJS) connection which (apparently) transfers huge amounts of data.
Turns out that Netty apparently has a content length maximum -- when I trip that limit in my SockJS route, I get this error:
2018-06-22 16:47:58.740 ERROR 11164 --- [ctor-http-nio-5] r.ipc.netty.channel.ContextHandler : Error cannot be forwarded to user-facing Mono
io.netty.handler.codec.TooLongFrameException: content length exceeded 65536 bytes.
at io.netty.handler.codec.MessageAggregator.handleOversizedMessage(MessageAggregator.java:399) [netty-codec-4.1.24.Final.jar:4.1.24.Final]
at io.netty.handler.codec.MessageAggregator.invokeHandleOversizedMessage(MessageAggregator.java:383) [netty-codec-4.1.24.Final.jar:4.1.24.Final]
at io.netty.handler.codec.MessageAggregator.decode(MessageAggregator.java:277) [netty-codec-4.1.24.Final.jar:4.1.24.Final]
at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:88) [netty-codec-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310) [netty-codec-4.1.24.Final.jar:4.1.24.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284) [netty-codec-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459) [netty-transport-4.1.24.Final.jar:4.1.24.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884) [netty-common-4.1.24.Final.jar:4.1.24.Final]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_161]
How do I configure the embedded Netty in spring-boot to not have a content length limit? I have no control over the length of the message being returned in the response.
The route in the gateway looks like this:
- id: check_status_sockjs
uri: http://foo.example.com:8080
predicates:
- Path=/foo/status/**
filters:
- RewritePath=/foo/status/(?<segment>.*), /status/$\{segment}
The service at the other end that I'm routing the sockJS request to is a Spring-Boot app as well, deployed as a war in a Tomcat 8.5 server. When I interact directly with the backing service, I do not run into any issues with this content length stuff -- it's only when I try to route through the embedded Netty in my gateway app.
I also successfully send and receive smaller messages across this route -- it's only when I hit this apparent length limit does it explode.
My dependencies in the gateway are this:
It is now possible using the following boms:
dependencyManagement {
imports {
mavenBom("org.springframework.boot:spring-boot-dependencies:2.2.2.RELEASE")
mavenBom("org.springframework.cloud:spring-cloud-dependencies:Hoxton.RELEASE")
}
}
And then in your gateway application config you can set:
spring.cloud.gateway.httpclient.websocket.max-frame-payload-length: <bytes_new_limit>
I was struggling with this for a while, my spring boot was on '2.1.10.RELEASE'. They fixed it in the new version of webflux that comes with those managed dependencies.