使用Server Bootstrap进行定制后,Netty服务器不处理HTTP请求

问题描述 投票:0回答:1

我有一个基于 Spring React 的微服务,它使用 Netty Server 版本 4.1.101.Final。 它工作得很好并处理我触发的所有 HTTP 请求。现在我想捕获连接 ID 以找出哪个连接正在使用以及哪个连接正在关闭。为此,我编写了一个自定义连接日志记录处理程序。以下是我的 ConnectionLoggingHandler :

public class ConnectionLoggingHandler extends ChannelInboundHandlerAdapter{
    private static final AtomicInteger connectionIdCounter = new AtomicInteger(0);
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception{
        int connectionId=connectionIdCounter.incrementAndGet();
        System.out.println("Connection established : ID = " + connectionId);
        ctx.channel().attr(AttributeKey.valueOf("connectionId")).set(connectionId);
        super.channelActive(ctx);
    }
    
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception{
        //retrieve connectionID
        Integer connectionId = (Integer) ctx.channel().attr(AttributeKey.valueOf("connectionId")).get();
        if(connectionId!=null){
          System.out.println("Connection closed : ID = " + connectionId);  
        }
        super.channelInactive(ctx);
    }
    
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception{
        //retrieve connectionID
        Integer connectionId = (Integer) ctx.channel().attr(AttributeKey.valueOf("connectionId")).get();
        if(connectionId!=null){
          System.out.println("Exception in Connection: ID = " + connectionId);  
        }
        cause.printStackTrace();
        ctx.close();
    }
}

现在我想将此处理程序添加到我的 Netty 服务器中。我用两种方法尝试过。

自定义 Netty 服务器代码:

public class CustomNettyServer{
    private int port =8080;
    
    @PostConstruct
    public void startServer() throws InterruptedException{
        EventLoopGroup boss= new NioEventLoopGroup();
        EventLoopGroup worker=new NioEventLoopGroup();
        try{
            ServerBootstrap bootstrap new ServerBootstrap();
            bootstrap.group(boss,worker)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<Channel>(){
                    @Override
                    protected void initChannel(Channel ch) throws Exception{
                        ch.pipeline().addLast(new HttpServerCodec(),new HttpRequestDecoder(),new HttpContentDecompressor(),new HttpResponseEncoder(),new HttpContentCompressor(),new HttpObjectAggregator(512*1024),new ConnectionLoggingHandler());
                        
                    }
                });
            Channel channel = bootstarp.bind(port).sync().channel();
            channel.closeFuture().sync();
        }
        finally{
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }
}

当我使用此服务器时,当我通过邮递员发出建立连接的请求时,我可以看到自定义处理程序中存在的日志。但我的 HTTP 请求没有得到处理。
它显示已丢弃入站消息。请检查您的管道配置。我不知道我在这里缺少什么。

然后我还尝试了另一种方法来定制我的netty服务器。下面是我的 CustomNettyServer 代码。

public class CustomNettyServer implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory>{
    @Override
    public void customize(NettyReactiveWebServerFactory factory){
        factory.addServerCustomizers(server->
        server.tcpConfiguration(tcp->
        tcp.doOnConnection(connection->
        connection.addHandlerLast(new ConnectionLoggingHandler()))));
    }
}

使用此方法,每当我点击请求并且请求成功处理时,由于我的 ConnectionLoggingHandler,我无法看到日志被打印。我可以看到 Handler 在发出请求时添加到管道中,并在处理请求时删除。但日志没有生成。我还将日志记录级别保持为 DEBUG。

我不知道我在这两种方式上做错了什么,我被困在这里。
所以我想知道如何获取正在打开、使用和关闭的 Connection-ID 的日志。
谢谢。

httprequest netty httpserver httpconnection reactor-netty
1个回答
0
投票

Reactor Netty(Spring WebFlux 使用的默认运行时)不使用 Netty 提供的 Bootstrap 类。

扩展 Reactor Netty 的正确方法是通过生命周期回调。 在您的示例中,您使用的是

doOnConnection
,但此时通道已经处于活动状态,并且您在
ConnectionLoggingHandler#channelActive
下的实现将永远不会被调用(检查 javadoc 中的 addHandlerLast)。 你最好使用回调
doOnChannelInit
,如下

@Component
public class CustomNettyServer
        implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
    @Override
    public void customize(NettyReactiveWebServerFactory factory) {
        factory.addServerCustomizers(server ->
                server.doOnChannelInit((obs, ch, addr) ->
                        ch.pipeline().addAfter(NettyPipeline.HttpCodec, "test", new ConnectionLoggingHandler())));
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.