Отправка незапрашиваемого ответа 408 от Netty на тайм-аут соединения - PullRequest
0 голосов
/ 23 июня 2019

Согласно спецификации HTTP-сервер должен отправить 408, если он не получил запрос в течение определенного времени.Это немного не интуитивно понятно, так как это означает, что вы можете отправить ответ, не получив запроса.Одна из целей - уничтожить долгоживущие HTTP-соединения с поддержкой активности 1.1, которые клиенты еще не закрыли.

Для этого я добавил событие IdleStateEvent и там:

DefaultFullHttpResponse resp = new DefaultFullHttpResponse(HTTP_1_1, 
                                          HttpResponseStatus.REQUEST_TIMEOUT);
resp.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
ctx.writeAndFlush(resp)
    .addListener(future -> {
        System.out.println("Finished " + future.cause());
    })
    .addListener(ChannelFutureListener.CLOSE);

И вывод:

Finished io.netty.handler.codec.EncoderException: java.lang.IllegalStateException: cannot send more responses than requests

Есть ли способ сделать это в Netty?Или рекомендуемый способ закрыть неактивные соединения HTTP 1.1?

1 Ответ

0 голосов
/ 23 июня 2019

В соответствии с Netty javadoc , вы можете использовать класс IdleStateHandler для закрытия незанятых соединений.По-видимому, этот обработчик будет вызывать IdleStateEvent, когда в течение некоторого времени в соединении нет ни чтения, ни записи, либо обоих.Затем это событие можно использовать для запуска отключения соединения ... или для других действий.

Следующий пример скопирован из javadoc:

 // An example that sends a ping message when there is no outbound traffic
 // for 30 seconds.  The connection is closed when there is no inbound traffic
 // for 60 seconds.

 public class MyChannelInitializer extends ChannelInitializer<Channel> {
      @Override
     public void initChannel(Channel channel) {
         channel.pipeline().addLast("idleStateHandler", new IdleStateHandler(60, 30, 0));
         channel.pipeline().addLast("myHandler", new MyHandler());
     }
 }

 // Handler should handle the IdleStateEvent triggered by IdleStateHandler.
 public class MyHandler extends ChannelDuplexHandler {
      @Override
     public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
         if (evt instanceof IdleStateEvent) {
             IdleStateEvent e = (IdleStateEvent) evt;
             if (e.state() == IdleState.READER_IDLE) {
                 ctx.close();
             } else if (e.state() == IdleState.WRITER_IDLE) {
                 ctx.writeAndFlush(new PingMessage());
             }
         }
     }
 }

 ServerBootstrap bootstrap = ...;
 ...
 bootstrap.childHandler(new MyChannelInitializer());
 ...

Примечание: в соответствии с это Q & A , IdleStateHandler должен быть первым обработчиком в конвейере.

...