处理netty

时间:2016-11-24 12:05:34

标签: java http netty

我对netty相对较新,不确定我是否正确行事。我会尽量缩短。如果有任何不清楚的地方,请询问更多信息。

因此,我有一个服务于HTTP请求的netty服务器,其中内容应该是序列化为Json字符串的protobuf消息。

频道管道如下所示:

@Override protected void initChannel(final SocketChannel channel) throws Exception {
    final ChannelPipeline pipeline = channel.pipeline();
    pipeline.addLast(new HttpServerCodec());
    pipeline.addLast(new HttpObjectAggregator(1048576));
    pipeline.addLast(new HttpProtobufServerCodec(charset, requestConverter, responseConverter));
    pipeline.addLast(new ProtobufMessageHandler(mapping));
}

前两个渠道处理程序是标准的网络资源,

HttpProtobufServerCodec看起来像:

public class HttpProtobufServerCodec extends CombinedChannelDuplexHandler<HttpToProtobufDecoder, ProtobufToHttpEncoder>

和HttpToProtobufDecoder看起来像:

public final class HttpToProtobufDecoder extends MessageToMessageDecoder<FullHttpRequest> {
    private Charset charset;
    private final Converter<byte[], ?> converter;

    protected HttpToProtobufDecoder(final Charset charset, final Converter<byte[], ?> converter) {
        this.charset = charset;
        this.converter = converter;
    }

    @Override protected void decode(final ChannelHandlerContext ctx, final FullHttpRequest msg, final List<Object> out)
            throws Exception {
        byte[] payloadBytes = new byte[msg.content().readableBytes()];
        msg.content().readBytes(payloadBytes);
        Message message = (Message) converter.convert(payloadBytes);
        out.add(message);
    }

    @Override public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
        FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, 
                    HttpResponseStatus.BAD_REQUEST, 
                    Unpooled.wrappedBuffer(charset.encode("Could not read request!").array()));

        //ctx.writeAndFlush(response);
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }
}

因此,我在HttpToProtobufDecoder中收到了一个FullHttpRequest,并尝试将请求的内容解码为protobuf消息。如果无法对内容进行解码,这会将我们置于exceptionCaught(...)方法中,则会引发异常。

在异常中捕获了一个HTTP 400响应,并将其写入channelHandlerContext。这是我有疑问的地方。

如果切换以下行的评论:

//ctx.writeAndFlush(response);
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);

客户在阅读回复正文时会超时。但是如果我在写完400后关闭频道,一切似乎都很好。会发生什么;由于没有可用的输入数据,因此阻止了输入流的读取。即我们被困在下面的in.read(...)中,远离客户代码中的某个地方:

while ((bytesRead = in.read(buffer)) != -1) {
        out.write(buffer, 0, bytesRead);
        byteCount += bytesRead;
    }

所以,问题是,在出于某种原因编写http 400响应后,您是否关闭了频道?

我是否以正确的方式解决这个问题?我应该在exceptionCaught中编写HTTP响应消息吗?

很抱歉,如果问题有点不清楚。任何帮助将不胜感激!

/谢谢!

1 个答案:

答案 0 :(得分:2)

客户端无法知道您的邮件何时完全发送。添加内容长度或分块标头,您将不再需要关闭连接。