【问题标题】:Using Netty as a basic transparent HTTP proxy使用 Netty 作为基本的透明 HTTP 代理
【发布时间】:2020-05-12 20:35:26
【问题描述】:

我需要实现一个充当透明 HTTP 代理的服务,它需要执行以下操作:

  1. 接收 HTTP 请求(TLS 已经终止,所以我们在这里只讨论普通 HTTP)
  2. 向请求添加标头
  3. 以非阻塞方式将修改后的请求转发到其预期目的地
  4. 存储/挂起请求以供以后使用
  5. 当响应返回时,将其返回给调用者。
  6. 打包响应和请求(隐藏在 #4 中)并以非阻塞方式将它们发送到另一个系统。

阅读 Netty 文档后,我设法将一些非常原始的东西放在一起,它接受来自客户端的 HTTP 请求并返回 HTTP 响应,这在单个服务器管道中使用了以下 Netty 组件:

  • HttpServerCodec
  • HttpObjectAggregator
  • 我写的一个处理程序,它扩展了ChannelInboundHandlerAdapter,看起来像这样:

    void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
        try {
            FullHttpRequest httpRequest = (FullHttpRequest) msg
            ensureAuditingHeaderIsPresent(httpRequest)
            ctx.writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK))
            println("Response written...")
        }
        finally {
            ReferenceCountUtil.release(msg)
        }
    }```
    

这一切都如我所料,导致向客户端返回 200 响应(尽管是空的)。但是,我很难理解我现在可以采用哪种方法来实现 HTTP 请求的转发以及将响应返回给客户端。

我最初的想法是使用异步 HTTP 客户端库,但我觉得我缺少 Netty 内置的一些东西,它可以让我在管道中做到这一点?也许某种出站ChannelOutboundHandlerAdapter

如您所知,我目前对 Netty 内部的理解非常基础,非常感谢任何指点!

最后一个问题:2015 年的网络实战书还值得一读吗?如果它会完全过时,我不愿意购买它,但它仍然具有相关性,那么可能值得一读?

非常感谢,

艾德

【问题讨论】:

    标签: netty


    【解决方案1】:

    您将需要两条管道 - 一条用于服务器端(也称为传入通道),一条用于客户端(也称为传出通道)到目标服务器。一旦您从传入通道的处理程序接收到请求,您将需要启动与目标服务器的新连接并传递 a) HTTP 请求(根据需要进行修改)和 b) 对传入通道上下文的引用。一旦您从目标服务器接收到来自您的传出通道处理程序的响应,您就可以简单地将响应(根据需要进行修改)写回传入通道。无需外部库。

    一个(非常简化的)伪代码示例,为您指明正确的方向:

    您的服务器端处理程序如下所示:

    void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
        try {
            FullHttpRequest httpRequest = (FullHttpRequest) msg;
            ensureAuditingHeaderIsPresent(httpRequest);
            Bootstrap b = new Bootstrap();
            b.group(eventLoopGroup) // use the same eventLoopGroup as the server's
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new HttpClientCodec())
                                         .addLast(new HttpObjectAggregator())
                                         .addLast(new MyProxyOutgoingChannelHandler(httpRequest.copy(), ctx));
                        }
                    });
            String targetHost = getTargetHostFromRequest(httpRequest);
            int targetPort = getTargetPortFromRequest(httpRequest);
            b.connect(targetHost, targetPort);
        }
        finally {
            ReferenceCountUtil.release(msg);
        }
    }
    

    您的传出通道处理程序将如下所示:

    class MyProxyOutgoingChannelHandler extends SimpleChannelInboundHandler {
    
        private final ChannelHandlerContext incomingChannelCtx;
        private final HttpRequest httpRequest;
    
        void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
            FullHttpResponse response = (FullHttpResponse) msg;
            incomingChannelCtx.writeAndFlush(response);
        }
    
        @Override
        void channelActive(ChannelHandlerContext ctx) throws Exception {
            ctx.write(httpRequest);
        }
    

    Re: Netty In Action,我自己没有读过,但作者 Norman Maurer 仍然是项目负责人,我毫不怀疑书中的概念仍然相关,即使代码示例可能是过时了。

    希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-22
      • 2011-06-11
      • 1970-01-01
      • 1970-01-01
      • 2015-05-07
      • 1970-01-01
      • 2015-10-17
      相关资源
      最近更新 更多