Как заставить Netty обслуживать / принимать веб-сокет из веб-приложения, обслуживаемого на другом сервере («узле») на другом порту - PullRequest
0 голосов
/ 16 февраля 2019

Я играю с веб-сокетом в Angular 7 webapp.Идея состоит в том, чтобы веб-приложение обслуживалось узлом - например, по адресу:

http://localhost:4200/

и веб-сокетом по другому адресу и порту, обслуживаемому приложением Netty / Java.

НаВеб-приложение Я перехожу на страницу веб-сокета.Для ввода адреса веб-сокета есть текстовое поле и кнопка «Подключиться», которая соединяет нас с сервером веб-сокетов.Например, тест по этому адресу работает нормально:

ws://echo.websocket.org          // works - we get a response
or
ws://echo.websocket.org:80       // works - we get a response

Вместо этого я хочу, чтобы сервер Netty обслуживал веб-сокет.Запускаю сервер - обслуживает по адресу:

http://localhost:8081/

и работает нормально.(Я могу подключиться из отдельного окна браузера и страницы веб-сокета, обслуживаемой сервером по этому адресу и порту).

Но теперь я хочу подключиться к серверу Netty из моего веб-приложения на - localhost: 4200/.Итак, я предоставляю этот адрес для сокетного соединения;

ws://localhost:8081/

и нажимаю «Подключиться».

Сервер Netty реагирует на этот журнал (все строки отображаются одновременно):

Feb 16, 2019 7:26:20 AM io.netty.handler.logging.LoggingHandler channelRead
INFO: [id: 0xfd77a1f7, L:/0:0:0:0:0:0:0:0:8081] READ: [id: 0x24ad1bc1, L:/127.0.0.1:8081 - R:/127.0.0.1:51928]
Feb 16, 2019 7:26:20 AM io.netty.handler.logging.LoggingHandler channelReadComplete
INFO: [id: 0xfd77a1f7, L:/0:0:0:0:0:0:0:0:8081] READ COMPLETE
Websocke channel Active:[id: 0x24ad1bc1, L:/127.0.0.1:8081 - R:/127.0.0.1:51928]
Websocke channel Inactive:[id: 0x24ad1bc1, L:/127.0.0.1:8081 ! R:/127.0.0.1:51928]
Websocke channel Unregistered:[id: 0x24ad1bc1, L:/127.0.0.1:8081 ! R:/127.0.0.1:51928]

Вероятно, это означает, что связь работает, однако Netty не принимает и отключает веб-сокет.

Это мои обработчики в конвейере Netty:

    new HttpServerCodec());
    new HttpObjectAggregator(65536));
    new WebSocketServerCompressionHandler());
    new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true));
              // Next handler serves index.html page
              //   ... extends SimpleChannelInboundHandler<FullHttpRequest>
              //       @Override
              //      protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {
    new WebSocketIndexPageHandlerA1(WEBSOCKET_PATH));
              // Next handler handles websocket communication
              //   ... extends SimpleChannelInboundHandler<WebSocketFrame>
              //       @Override
              //      protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
    new WebSocketFrameHandlerA1());

Как заставить Netty принять этот запрос веб-сокета и передать поток по конвейеру моему последнему обработчику - обработчику сообщений веб-сокета - WebSocketFrameHandlerA1, чтобы он мог отвечать клиенту (-ам) веб-сокета - откуда бы они ни исходили?

1 Ответ

0 голосов
/ 19 февраля 2019

Этот вопрос имеет довольно прямой и логичный ответ.Нам просто нужно оснастить наши конвейерные обработчики Netty, соответствующие ожидаемому трафику (HTTP / Websockets и т. Д.) От клиента (ов).

Итак, если мы попытаемся подключиться к Netty, используя:

ws://localhost:8081/

сервер получит начальный HTTP-запрос - что-то вроде этого:

GET / HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Sec-WebSocket-Version: 13
Origin: http://localhost:4200
Sec-WebSocket-Extensions: permessage-deflate
Sec-WebSocket-Key: XVXVXS%GDDD+lDfDS==
Connection: keep-alive, Upgrade
Cookie: _ga=GA1.1.1146780314.5634479786
Pragma: no-cache
Cache-Control: no-cache
Upgrade: websocket
Connection : keep-alive, Upgrade
Upgrade : websocket

Мы должны убедиться, что у нас есть правильные обработчики в конвейере, чтобы обработать начальный HTTP-запрос, а затем обновить/ переключиться на обработчик websocket.В этом случае начальный конвейер может быть таким простым:

pipeline.addLast("httpServerCodec", new HttpServerCodec());
pipeline.addLast("httpHandler", new HttpServerHandler());

Далее в HttpServerHandler включите:

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {

        if (msg instanceof HttpRequest) {

            HttpRequest httpRequest = (HttpRequest) msg;
            HttpHeaders headers = httpRequest.headers();

            if (headers.get(HttpHeaderNames.CONNECTION).toUpperCase().contains("UPGRADE") &&
            headers.get(HttpHeaderNames.UPGRADE).toUpperCase().contains("WEBSOCKET")) {

                // Replace the HTTP handler with a websocket handler
                // in the existing pipeline to handle WebSocket Messages
                ctx.pipeline().replace(this, "websocketHandler", new WebSocketHandler());
                //Do the Handshake to upgrade connection from HTTP to WebSocket protocol
            handleHandshake(ctx, httpRequest);
        }
        ...
      }

В ваш обработчик websocket вставьте логику обмена данными междуклиент и сервер.

...