我有一个已启动并正在运行的Netty代理服务器。 netty收到httpRequest后,将执行以下操作
1)MainHandler#channelRead方法创建一个FullHttpRequest对象,该对象将传递到另一个方法。在这种方法中,我克隆了fullHttpRequest对象,修改了内容(请求主体),使用SubHandler创建了一个客户端bootStrap,并向远程服务器发出了带有修改后的对象的请求。
完成此处理后,我将原始请求对象代理到远程服务器。
我观察到的是,如果我注释掉invokeAndParseClient
(这是客户端引导程序),则代理可以正常工作。
如果包含invokeAndParseClient
,则会出错(下面的stacktrace)
注意:异常是从proxyRequest抛出的,而不是invokeAndParseClient。
这是启示代码
class MainHandler extends ChannelDuplexHandler {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
if (msg instanceof HttpRequest) {
FullHttpRequest request = (FullHttpRequest) msg;
invokeAndParseClient(request);
proxyRequest(ctx, request);
}
}
public void invokeAndParseClient(FullHttpRequest request) {
FullHttpRequest dup = req.duplicate();
ByteBuf content = dup.content().copy();
String newContent = modifiedContent(content); //modifies content to String, do some String replacments
ByteBuf buf = Unpooled.wrappedBuffer(newContent.getBytes(Charset.forName("UTF-8")));
dup.replace(buf); //replace content on the request
BootStrap b = new Bootstrap()
.group(bossGroup())
.channel(NioSocketChannel.class)
.handler(new RemoteChannelInitializer());
Channel ch = bootstrap.connect(remoteSocketAddress).sync().channel();
ChannelFuture f = ch.writeAndFlush(clonedReq);
//need to close channel. but have to figure out when
}
public class RemoteChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
public void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new HttpClientCodec());
p.addLast(new HttpObjectAggregator(1024 * 1024, true));
p.addLast(new ClientHandler()));
}
}
public class ClientHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(ClientRequestHandler.class);
@Override
public void channelRead(final ChannelHandlerContext ctx, Object msg) {
LOGGER.info("here you gooooo");
if (msg instanceof FullHttpResponse) {
LOGGER.info("this is fullHttpResponse");
FullHttpResponse full = (FullHttpResponse) msg;
FullHttpResponse dup = full.copy();
LOGGER.info("response code ===> " + full.status());
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
}
使用此代码,我得到以下异常。但是一旦我注释掉invokeAndParseClient(request),它就可以正常工作。 这是什么问题?
2019-05-21 16:08:59.524 WARN 45091 --- [tLoopGroup-3-25] io.netty.channel.ChannelOutboundBuffer : Failed to mark a promise as success because it has failed already: DefaultChannelPromise@2e4d789f(failure: io.netty.handler.codec.EncoderException: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1), unnotified cause:
io.netty.handler.codec.EncoderException: io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:106) ~[netty-codec-4.1.31.Final.jar:4.1.31.Final]
at io.netty.channel.CombinedChannelDuplexHandler.write(CombinedChannelDuplexHandler.java:348) ~[netty-transport-4.1.31.Final.jar:4.1.31.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeWrite0(AbstractChannelHandlerContext.java:738) ~[netty-transport-4.1.31.Final.jar:4.1.31.Final]
at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush(AbstractChannelHandlerContext.java:801) ~[netty-transport-4.1.31.Final.jar:4.1.31.Final]
at io.netty.channel.AbstractChannelHandlerContext.write(AbstractChannelHandlerContext.java:814) ~[netty-transport-4.1.31.Final.jar:4.1.31.Final]
at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:794) ~[netty-transport-4.1.31.Final.jar:4.1.31.Final]
at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush(AbstractChannelHandlerContext.java:837) ~[netty-transport-4.1.31.Final.jar:4.1.31.Final]
at io.netty.channel.DefaultChannelPipeline.writeAndFlush(DefaultChannelPipeline.java:1071) ~[netty-transport-4.1.31.Final.jar:4.1.31.Final]
at io.netty.channel.AbstractChannel.writeAndFlush(AbstractChannel.java:300) ~[netty-transport-4.1.31.Final.jar:4.1.31.Final]
at com.example.MainHandler.proxyRequest(ClientRequestHandler.java:178) ~[classes/:na]