前言:
在 Spring Cloud Gateway 3.1.4 版本中配置 WebSocket 通信时,遇到 Max frame length of 65536 has been exceeded
错误。经过源码分析发现,网上流传的通过 spring.cloud.gateway.httpclient.websocket.max-frame-payload-length
配置参数修改最大帧长度的方法无效。本文通过源码解析问题根源,并提供有效解决方案。
问题现象
WebSocket 配置伪代码
typescript
@Autowired
@Bean
public HandlerMapping webSocketMapping(final EchoHandler echoHandler) {
Map<String, WebSocketHandler> map = new HashMap<>();
map.put("/echo", echoHandler);
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
mapping.setOrder(Ordered.HIGHEST_PRECEDENCE);
mapping.setUrlMap(map);
return mapping;
}
@Bean
public WebSocketHandlerAdapter handlerAdapter() {
return new WebSocketHandlerAdapter(); // 问题关键在这里
}
即使配置了:
yaml
spring:
cloud:
gateway:
httpclient:
websocket:
max-frame-payload-length: xxxxxx
仍然会触发默认最大帧长度 65536 的限制错误。
为什么配置了 max-frame-payload-length
却无效?
这要从 WebSocketHandlerAdapter
的源码开始分析。
csharp
public WebSocketHandlerAdapter() {
this(new HandshakeWebSocketService()); // 使用默认HandshakeWebSocketService
}
HandshakeWebSocketService
的默认构造器如下:
csharp
// gateway 使用的是reactor netty 所以最后初始化出来的是ReactorNettyRequestUpgradeStrategy
public HandshakeWebSocketService() {
this(initUpgradeStrategy()); // 初始化 ReactorNettyRequestUpgradeStrategy
}
默认会使用 ReactorNettyRequestUpgradeStrategy
:
csharp
public ReactorNettyRequestUpgradeStrategy() {
this(WebsocketServerSpec::builder); // 使用无参 builder
}
进一步查看 WebsocketServerSpec.Builder
的实现:
scala
public static class Builder<SPEC extends Builder<SPEC>> implements Supplier<SPEC> {
int maxFramePayloadLength = 65536; // 默认值
...
}
结论
Spring Cloud Gateway 的 spring.cloud.gateway.httpclient.websocket.max-frame-payload-length
配置项实际上无法修改底层 WebsocketServerSpec
的 maxFramePayloadLength
值,因为默认构造方式不会读取该配置。
有效解决方案
我们可以自己构建一个带参数的 ReactorNettyRequestUpgradeStrategy
,明确设置 maxFramePayloadLength
通过显式配置 ReactorNettyRequestUpgradeStrategy
并自定义 WebsocketServerSpec
:
java
@Bean
public WebSocketHandlerAdapter handlerAdapter() {
int frameSizeLimit = 655360; // 设置为你所需的帧长度限制
WebsocketServerSpec.Builder builder = WebsocketServerSpec.builder().maxFramePayloadLength(frameSizeLimit);
ReactorNettyRequestUpgradeStrategy upgradeStrategy = new ReactorNettyRequestUpgradeStrategy(builder);
return new WebSocketHandlerAdapter(new HandshakeWebSocketService(upgradeStrategy));
}
补充说明
若需要配置更多 WebSocket 参数(如启用压缩、调整 Ping/Pong 处理策略),可在 WebsocketServerSpec.Builder
中链式调用:
scss
WebsocketServerSpec.Builder builder = WebsocketServerSpec.builder()
.maxFramePayloadLength(655360)
.compress(true) // 启用压缩
.handlePing(false); // 禁止自动处理Ping帧
总结:
-
spring.cloud.gateway.httpclient.websocket.max-frame-payload-length
是 针对gateway
客户端通信(即作为 WebSocket 客户端)配置的; -
如果你是通过自定义
WebSocketHandlerAdapter
来处理 WebSocket 请求(即作为 WebSocket 服务端),则必须手动指定maxFramePayloadLength
; -
默认构造路径中的帧大小限制是写死在源码中的,必须通过构造器覆盖。