maxframelength 是 netty 帧解码器中防止 oom 的长度限制机制,单位为字节,需配合 lengthfieldbasedframedecoder 等使用;它不防连接滥用,但能避免超长帧耗尽堆外内存,须捕获 toolongframeexception 并立即关闭连接。

Netty 的 MaxFrameLength 是什么,它真能防攻击吗
不能直接防攻击,它只是帧解析层面的长度守门员。当客户端发来一个超长的帧(比如 WebSocket 或自定义协议里单个消息体超过设定值),MaxFrameLength 会在解码阶段抛出 TooLongFrameException,而不是让数据进内存再判断——这是关键:它防止的是 OOM,不是连接滥用。
常见错误现象:OutOfMemoryError: Direct buffer memory 或服务端 CPU 突升、GC 频繁,但日志里没明显报错;其实可能是巨型帧反复触发解码器分配大缓冲区,最终耗尽堆外内存。
-
MaxFrameLength必须配合具体解码器使用,比如LengthFieldBasedFrameDecoder、WebSocketFrameDecoder,单独设置无效 - 它的单位是字节,不是消息个数,也不是字符数;UTF-8 下一个中文占 3 字节,别按字符串长度硬算
- 设得太小会误杀合法大文件上传(如 base64 图片),太大会失去防护意义;建议从 1MB 起调,结合业务最大单次载荷定
捕获 TooLongFrameException 后必须立刻关闭连接
很多人只加了 MaxFrameLength,却没处理异常,结果异常被吞掉或仅打日志,恶意客户端可以持续重连发包,形成低频慢速 DoS。
正确做法是在 exceptionCaught 中识别该异常并强制关闭,且不给任何响应(避免暴露服务状态):
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
if (cause instanceof TooLongFrameException) {
ctx.close(); // 不要 writeAndFlush 错误响应
return;
}
// 其他异常按需处理
}- 不要在关闭前调用
ctx.writeAndFlush(...),哪怕只是发个 "bad request" —— 这会增加响应负担,也可能被用于探测 - 确保
ctx.close()在事件链中尽快执行;如果用了SimpleChannelInboundHandler,注意它默认会释放消息,但异常路径不受影响 - 某些 Netty 版本(如 4.1.90+)对
TooLongFrameException做了优化,自动触发 close,但仍建议显式判断,兼容旧版本
HTTP/HTTPS 场景下 MaxFrameLength 不起作用
HTTP 协议本身没有“帧”概念,MaxFrameLength 对 HttpObjectDecoder 无效。想限制 HTTP 请求体大小,得用 HttpObjectAggregator 的 maxContentLength 参数,或者更前置地用 HttpServerCodec 后接自定义拦截。
典型误用:在 WebSocket over HTTP 升级后,仍用 HTTP 解码器限制,结果 WebSocket 帧照样能超长穿透。
- WebSocket 连接建立后,走的是
WebSocketFrameDecoder,此时MaxFrameLength才生效 - HTTP POST 的 body 限制必须独立配置,例如:
new HttpObjectAggregator(1024 * 1024)表示最多聚合 1MB 的内容 - 若用 Spring WebFlux 或其他上层框架,优先用框架提供的请求体限制(如
spring.codec.max-in-memory-size),避免重复控制
连接空闲 + 巨型帧双触发时的资源泄漏风险
如果客户端在发送巨型帧的同时还长期不发心跳,可能触发两个机制叠加:空闲超时关闭 + 帧超长异常。Netty 默认不会自动清理未完成解码的缓冲区,容易导致 PooledByteBufAllocator 的内存池泄漏。
这不是理论问题,线上见过因该组合导致 direct memory 每小时涨 50MB 的案例。
- 务必在
channelInactive和exceptionCaught中手动调用ctx.channel().closeFuture().addListener(...)清理残留引用 - 启用 Netty 内存泄露检测(
-Dio.netty.leakDetectionLevel=advanced)只适合调试,生产环境必须关,但上线前应跑过压力测试验证无泄漏 - 对高危协议(如自定义二进制协议),建议在解码器构造时传入
true开启failFast模式,让异常在首次读取就抛出,而非等整个帧收完
真正难防的不是单次巨型包,而是客户端一边保持连接空闲,一边周期性发临界尺寸帧试探阈值——这种行为不会触发常规监控告警,但会缓慢拖垮连接池和内存池。










