You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Netty Server的HttpContentDecompressor移除请求头,能否配置保留?

解决Netty HttpContentDecompressor解压后保留原始Content-Encoding头的问题

默认情况下,io.netty.handler.codec.http.HttpContentDecompressor在完成请求解压后会移除content-encoding头——这符合HTTP规范,因为此时请求体已经是解压后的明文,该头原本的语义已经失效。但如果你的业务需要判断原始请求是否为压缩格式,可以通过以下两种方式实现需求:

方法一:自定义Decompressor保存原始头到自定义HTTP头

继承HttpContentDecompressor,重写decode方法,在父类处理前先把原始的content-encoding值复制到一个自定义头(比如X-Original-Content-Encoding)中,这样即使原头被移除,你依然能通过自定义头获取原始编码信息。

public class PreservingHttpContentDecompressor extends HttpContentDecompressor {

    @Override
    protected Object decode(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof FullHttpRequest) {
            FullHttpRequest request = (FullHttpRequest) msg;
            String originalEncoding = request.headers().get(HttpHeaderNames.CONTENT_ENCODING);
            if (originalEncoding != null) {
                // 添加自定义头存储原始编码
                request.headers().set("X-Original-Content-Encoding", originalEncoding);
            }
        }
        // 调用父类逻辑,父类会自动移除原content-encoding头
        return super.decode(ctx, msg);
    }
}

然后在Spring Boot的Netty服务器配置中,替换默认的HttpContentDecompressor为你自定义的实现:

@Configuration
public class NettyServerConfig {

    @Bean
    public NettyServerCustomizer nettyServerCustomizer() {
        return httpServer -> httpServer.tcpConfiguration(tcpServer ->
                tcpServer.bootstrap(serverBootstrap ->
                        serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ChannelPipeline pipeline = ch.pipeline();
                                // 遍历流水线找到默认的 decompressor 并替换
                                for (Map.Entry<String, ChannelHandler> entry : pipeline) {
                                    if (entry.getValue() instanceof HttpContentDecompressor) {
                                        pipeline.replace(entry.getKey(), "preserving-decompressor", new PreservingHttpContentDecompressor());
                                        break;
                                    }
                                }
                            }
                        })
                )
        );
    }
}

方法二:在Decompressor前添加Handler保存原始头到请求属性

如果不想修改Decompressor的逻辑,可以在流水线中HttpContentDecompressor之前添加一个自定义的ChannelInboundHandlerAdapter,把原始的content-encoding值存入请求的属性中,后续业务逻辑可以直接从属性中读取。

public class ContentEncodingPreserverHandler extends ChannelInboundHandlerAdapter {
    // 定义属性键,用于存储原始编码
    private static final AttributeKey<String> ORIGINAL_CONTENT_ENCODING = AttributeKey.valueOf("ORIGINAL_CONTENT_ENCODING");

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof FullHttpRequest) {
            FullHttpRequest request = (FullHttpRequest) msg;
            String encoding = request.headers().get(HttpHeaderNames.CONTENT_ENCODING);
            if (encoding != null) {
                request.attr(ORIGINAL_CONTENT_ENCODING).set(encoding);
            }
        }
        super.channelRead(ctx, msg);
    }

    // 提供静态方法方便后续获取原始编码
    public static String getOriginalEncoding(FullHttpRequest request) {
        return request.attr(ORIGINAL_CONTENT_ENCODING).get();
    }
}

然后在Netty配置中把这个Handler加到Decompressor前面:

@Configuration
public class NettyServerConfig {

    @Bean
    public NettyServerCustomizer nettyServerCustomizer() {
        return httpServer -> httpServer.tcpConfiguration(tcpServer ->
                tcpServer.bootstrap(serverBootstrap ->
                        serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ChannelPipeline pipeline = ch.pipeline();
                                // 在默认的 decompressor 前添加自定义Handler
                                pipeline.addBefore("decompressor", "content-encoding-preserver", new ContentEncodingPreserverHandler());
                            }
                        })
                )
        );
    }
}

后续在业务逻辑中,就可以通过ContentEncodingPreserverHandler.getOriginalEncoding(request)获取原始的压缩编码信息了。

内容的提问来源于stack exchange,提问作者V John

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 04:55:15