netty中处理HTTP客户端异常
Handle HTTP client exception in netty
我对 netty 还比较陌生,不确定自己做的是否正确。我会尽量简短。如有不明之处请追问。
所以,我有一个 netty 服务器服务于 HTTP 请求,其中的内容应该是序列化为 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));
}
前两个通道处理程序是标准的 netty 东西,
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 后关闭频道,一切似乎都很好。发生的事情是;读取输入流被阻塞,因为没有可用的输入数据。 IE。我们被困在下面的 in.read(...) 中,客户端代码中的某个地方:
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
byteCount += bytesRead;
}
所以,问题是,您是否出于某种原因在写入 http 400 响应后关闭了通道?
我的做法是否正确?我应该在 exceptionCaught 中写入 HTTP 响应消息吗?
抱歉,如果问题有点不清楚。任何帮助将不胜感激!
/谢谢!
客户端无法知道您的消息何时已完全发送。添加内容长度或分块 header,您将不再需要关闭连接。
我对 netty 还比较陌生,不确定自己做的是否正确。我会尽量简短。如有不明之处请追问。
所以,我有一个 netty 服务器服务于 HTTP 请求,其中的内容应该是序列化为 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));
}
前两个通道处理程序是标准的 netty 东西,
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 后关闭频道,一切似乎都很好。发生的事情是;读取输入流被阻塞,因为没有可用的输入数据。 IE。我们被困在下面的 in.read(...) 中,客户端代码中的某个地方:
while ((bytesRead = in.read(buffer)) != -1) {
out.write(buffer, 0, bytesRead);
byteCount += bytesRead;
}
所以,问题是,您是否出于某种原因在写入 http 400 响应后关闭了通道?
我的做法是否正确?我应该在 exceptionCaught 中写入 HTTP 响应消息吗?
抱歉,如果问题有点不清楚。任何帮助将不胜感激!
/谢谢!
客户端无法知道您的消息何时已完全发送。添加内容长度或分块 header,您将不再需要关闭连接。