使用 Netty 作为基本的透明 HTTP 代理



我需要实现一个充当透明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年的《行动中的网络》这本书还值得一读吗?如果它完全过时,我不愿意购买它,但它仍然相关,那么可能值得一读?

非常感谢,

埃德

需要两个管道 - 一个用于服务器端(也称为传入通道(,另一个用于面向目标服务器的客户端(也称为传出通道(。收到来自传入通道处理程序的请求后,您需要启动与目标服务器的新连接,并传递 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);
}

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

希望有帮助。

最新更新