Использование Netty в качестве базового c прозрачного HTTP-прокси - PullRequest
0 голосов
/ 27 января 2020

У меня есть требование для реализации службы, которая действует как прозрачный HTTP-прокси, она должна сделать следующее:

  1. Получить HTTP-запрос (TLS уже будет прерван, поэтому мы говорим просто HTTP здесь)
  2. Добавить заголовок к запросу
  3. Переслать измененный запрос в его целевое назначение неблокирующим образом
  4. Закрепить / повесить на запрос на последующее использование
  5. Когда ответ возвращается, верните его вызывающей стороне.
  6. Упакуйте ответ и запрос (спрятанный в # 4) и отправьте их другой системе в неблокирующая мода.

Прочитав документы Netty, мне удалось собрать воедино что-то очень примитивное, которое принимает HTTP-запрос от клиента и возвращает HTTP-ответ, поэтому используются следующие компоненты Netty. в конвейере одного сервера:

  • HttpServerCode c
  • HttpObjectAggregator
  • Обработчик, который я написал, w который расширяет 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-запроса и возврата ответа клиенту.

Сначала я хотел использовать asyn * 1044. * Клиентская библиотека HTTP, но у меня такое ощущение, что мне не хватает чего-то встроенного в Netty, что позволило бы мне сделать это в конвейере? Возможно, какой-то исходящий ChannelOutboundHandlerAdapter?

Как вы можете сказать, мое нынешнее понимание внутренних функций Netty очень основательно c, поэтому я благодарен за любые указатели!

Последний вопрос: является ли Книга «Нетти в действии 2015» все еще стоит прочитать? Я не хочу покупать его, если он будет полностью устаревшим, но если он по-прежнему актуален, может быть, стоит прочитать?

Большое спасибо,

Edd

1 Ответ

0 голосов
/ 29 января 2020

Вам понадобятся два конвейера - один для стороны сервера (он же входящий канал) и один для стороны клиента (он же исходящий канал) к целевому серверу. Получив запрос от обработчика входящего канала, вы захотите установить новое соединение с целевым сервером и передать а) HTTP-запрос (измененный по мере необходимости) и б) ссылку на контекст входящего канала. Как только вы получите ответ от целевого сервера, от вашего обработчика исходящего канала, вы можете просто записать ответ (измененный при необходимости) на входящий канал. Внешние библиотеки не требуются.

(очень упрощенный) пример псевдокода, указывающий правильное направление:

Ваш обработчик на стороне сервера будет выглядеть примерно так:

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, я сам не читал его, но автор Норман Маурер по-прежнему возглавляет проект, а у меня нет сомневаюсь, что концепции в книге по-прежнему актуальны, даже если примеры кода могут быть устаревшими.

Надеюсь, это поможет.

...