spring-cloud-gateway使用websocket出现Max frame length of 65536 has been exceeded

前言:

在 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 配置项实际上无法修改底层 WebsocketServerSpecmaxFramePayloadLength 值,因为默认构造方式不会读取该配置。

有效解决方案

我们可以自己构建一个带参数的 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

  • 默认构造路径中的帧大小限制是写死在源码中的,必须通过构造器覆盖。

相关推荐
用户990450177800911 分钟前
若依工作流主流方案对接
后端
触底反弹26 分钟前
🚀 Node.js path 和 fs 模块,从回调地狱到 async/await 的进化之路!
javascript·后端·node.js
Csvn1 小时前
Python 开发技巧 · 生成器(Generator)进阶 —— 从 yield 到 yield from,写出省内存的生产者-消费者模式
后端·python
geovindu1 小时前
CSharp: Dijkstra Algorithms
开发语言·后端·算法·c#
宠友信息2 小时前
内容社区源码多端数据协议与 Spring Boot 状态流转实现思路
java·spring boot·websocket·uni-app
掘金者阿豪2 小时前
听书别再被会员和广告打断:把NAS变成自己的私人有声图书馆
后端
拉长的苗条3 小时前
细说 ASP.NET Cache 及其高级用法
后端·asp.net
一路向北North3 小时前
Spring Security OAuth2.0(19):JWT令牌
java·后端·spring
奇牙coding1233 小时前
OpenAI Realtime API WebSocket 断连 4008/1006 怎么解决?不是 Key 失效,是实时多模态独有的会话超时规则
python·websocket·网络协议·ai
用户6757049885023 小时前
Beanstalkd 实战指南:原来延迟队列、异步任务可以如此简单丝滑!
后端·消息队列