Java中如何判断gzip压缩byte[]是否被多次压缩?Netty解压问题
解决Netty HttpContentDecompressor处理多次压缩请求的问题
方案1:检查数据是否为gzip格式
gzip压缩的数据开头有固定的魔数(0x1F 0x8B),可以通过判断字节数组的前两个字节识别是否仍处于压缩状态。实现一个简单的工具方法即可:
public static boolean isGzipped(byte[] data) { if (data == null || data.length < 2) { return false; } return (data[0] == (byte) 0x1F) && (data[1] == (byte) 0x8B); }
在HttpContentDecompressor解压完成后调用这个方法,若返回true则再次执行解压逻辑,直到数据不再是gzip格式。注意设置最大解压次数(比如3次),防止恶意嵌套压缩导致死循环。
方案2:自定义递归解压的Handler
继承HttpContentDecompressor,重写解压逻辑实现自动多次处理:
public class RecursiveHttpContentDecompressor extends HttpContentDecompressor { private static final int MAX_DECOMPRESS_TIMES = 3; private int decompressCount = 0; @Override protected void decode(ChannelHandlerContext ctx, HttpObject msg, List<Object> out) throws Exception { super.decode(ctx, msg, out); // 处理完整请求对象 if (msg instanceof FullHttpRequest) { FullHttpRequest request = (FullHttpRequest) msg; ByteBuf content = request.content(); byte[] data = new byte[content.readableBytes()]; content.readBytes(data); content.resetReaderIndex(); if (isGzipped(data) && decompressCount < MAX_DECOMPRESS_TIMES) { decompressCount++; FullHttpRequest newRequest = request.retain(); decode(ctx, newRequest, out); } } // 流式请求需先拼接完整内容再检查压缩状态,这里省略具体实现 } private boolean isGzipped(byte[] data) { if (data == null || data.length < 2) { return false; } return (data[0] == (byte) 0x1F) && (data[1] == (byte) 0x8B); } }
用这个自定义Handler替换原有的HttpContentDecompressor,即可自动处理多次压缩的请求,同时通过MAX_DECOMPRESS_TIMES限制解压次数避免资源耗尽。
注意事项
- 流式请求(分段的
HttpContent)需要先拼接完整请求体,再检查压缩状态,不能单独处理每个片段。 - 必须设置最大解压次数,防范恶意构造的无限嵌套压缩数据攻击。
内容的提问来源于stack exchange,提问作者V John
相关产品推荐
相关产品推荐

