增加或删除 Spring-Boot 的嵌入式 Netty 中的内容长度限制
Increase or remove content length restrictions in Spring-Boot's embedded Netty
我在一些现有的微服务前面放置了一个 Spring 云网关。它主要工作,但我有一个 websocket (SockJS) 连接,它(显然)传输大量数据。
原来 Netty 显然有一个最大内容长度——当我在我的 SockJS 路由中遇到这个限制时,我得到这个错误:
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.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]
如何将 spring-boot 中的嵌入式 Netty 配置为没有内容长度限制? 我无法控制返回消息的长度在回复中。
网关中的路由如下所示:
- id: check_status_sockjs
uri: http://foo.example.com:8080
predicates:
- Path=/foo/status/**
filters:
- RewritePath=/foo/status/(?<segment>.*), /status/$\{segment}
我将 sockJS 请求路由到另一端的服务也是一个 Spring-Boot 应用程序,在 Tomcat 8.5 服务器中部署为 war .当我直接与支持服务交互时,我不会 运行 遇到与此内容长度有关的任何问题——只有当我尝试通过我的网关应用程序中的嵌入式 Netty 进行路由时才会出现这种情况。
我也成功地通过这条路线发送和接收较小的消息——只有当我达到这个明显的长度限制时它才会爆炸。
我在网关中的依赖是这样的:
- spring-cloud-starter-gateway (2.0.0.RELEASE)
- spring-boot-starter-webflux (2.0.2.RELEASE)
- spring-boot-starter-actuator (2.0.2.RELEASE)
How do I configure the embedded Netty in spring-boot to not have a content length limit?
目前不可能。
参见 reactor-netty #223 and Spring Framework #16228。
分析:
Turns out that Netty apparently has a content length maximum
限制来自 reactor-netty
,而不是直接来自 Netty
。
限制来自 reactor. ... .WebsocketInbound
,一个 Java 接口,每帧最多聚合 65,536 字节。
我只能找到一个 class 实现了 WebsocketInbound
:HttpServerWSOperations
。 class 不会更改默认方法 WebsocketInbound.aggregateFrames
,因此 65k 字节的限制仍然存在。
HttpServerWSOperations
被final方法使用HttpServerOperations.withWebsocketSupport
并且直接实例化,所以你不能改变实现。
现在可以使用以下 boms:
dependencyManagement {
imports {
mavenBom("org.springframework.boot:spring-boot-dependencies:2.2.2.RELEASE")
mavenBom("org.springframework.cloud:spring-cloud-dependencies:Hoxton.RELEASE")
}
}
然后在您的网关应用程序配置中,您可以设置:
spring.cloud.gateway.httpclient.websocket.max-frame-payload-length: <bytes_new_limit>
我为此苦苦挣扎了一段时间,我的 spring 引导程序是“2.1.10.RELEASE”。他们在这些托管依赖项附带的新版本 webflux 中修复了它。
@Configuration
public class NettyConfiguration implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
@Value("${server.max-initial-line-length:65536}")
private int maxInitialLingLength;
@Value("${server.max-http-header-size:65536}")
private int maxHttpHeaderSize;
public void customize(NettyReactiveWebServerFactory container) {
container.addServerCustomizers(
httpServer -> httpServer.httpRequestDecoder(
httpRequestDecoderSpec -> {
httpRequestDecoderSpec.maxHeaderSize(maxHttpHeaderSize);
httpRequestDecoderSpec.maxInitialLineLength(maxInitialLingLength);
return httpRequestDecoderSpec;
}
)
);
}
}
这对我有用,我设置了 maxHeaderSize 和 maxInitialLineLength 参数
我在一些现有的微服务前面放置了一个 Spring 云网关。它主要工作,但我有一个 websocket (SockJS) 连接,它(显然)传输大量数据。
原来 Netty 显然有一个最大内容长度——当我在我的 SockJS 路由中遇到这个限制时,我得到这个错误:
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.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]
如何将 spring-boot 中的嵌入式 Netty 配置为没有内容长度限制? 我无法控制返回消息的长度在回复中。
网关中的路由如下所示:
- id: check_status_sockjs
uri: http://foo.example.com:8080
predicates:
- Path=/foo/status/**
filters:
- RewritePath=/foo/status/(?<segment>.*), /status/$\{segment}
我将 sockJS 请求路由到另一端的服务也是一个 Spring-Boot 应用程序,在 Tomcat 8.5 服务器中部署为 war .当我直接与支持服务交互时,我不会 运行 遇到与此内容长度有关的任何问题——只有当我尝试通过我的网关应用程序中的嵌入式 Netty 进行路由时才会出现这种情况。
我也成功地通过这条路线发送和接收较小的消息——只有当我达到这个明显的长度限制时它才会爆炸。
我在网关中的依赖是这样的:
- spring-cloud-starter-gateway (2.0.0.RELEASE)
- spring-boot-starter-webflux (2.0.2.RELEASE)
- spring-boot-starter-actuator (2.0.2.RELEASE)
How do I configure the embedded Netty in spring-boot to not have a content length limit?
目前不可能。 参见 reactor-netty #223 and Spring Framework #16228。
分析:
Turns out that Netty apparently has a content length maximum
限制来自 reactor-netty
,而不是直接来自 Netty
。
限制来自 reactor. ... .WebsocketInbound
,一个 Java 接口,每帧最多聚合 65,536 字节。
我只能找到一个 class 实现了 WebsocketInbound
:HttpServerWSOperations
。 class 不会更改默认方法 WebsocketInbound.aggregateFrames
,因此 65k 字节的限制仍然存在。
HttpServerWSOperations
被final方法使用HttpServerOperations.withWebsocketSupport
并且直接实例化,所以你不能改变实现。
现在可以使用以下 boms:
dependencyManagement {
imports {
mavenBom("org.springframework.boot:spring-boot-dependencies:2.2.2.RELEASE")
mavenBom("org.springframework.cloud:spring-cloud-dependencies:Hoxton.RELEASE")
}
}
然后在您的网关应用程序配置中,您可以设置:
spring.cloud.gateway.httpclient.websocket.max-frame-payload-length: <bytes_new_limit>
我为此苦苦挣扎了一段时间,我的 spring 引导程序是“2.1.10.RELEASE”。他们在这些托管依赖项附带的新版本 webflux 中修复了它。
@Configuration
public class NettyConfiguration implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
@Value("${server.max-initial-line-length:65536}")
private int maxInitialLingLength;
@Value("${server.max-http-header-size:65536}")
private int maxHttpHeaderSize;
public void customize(NettyReactiveWebServerFactory container) {
container.addServerCustomizers(
httpServer -> httpServer.httpRequestDecoder(
httpRequestDecoderSpec -> {
httpRequestDecoderSpec.maxHeaderSize(maxHttpHeaderSize);
httpRequestDecoderSpec.maxInitialLineLength(maxInitialLingLength);
return httpRequestDecoderSpec;
}
)
);
}
}
这对我有用,我设置了 maxHeaderSize 和 maxInitialLineLength 参数