exceptionCaught обработка ошибок ответа на запись вызывает исключение и бесконечный цикл вызова exceptionCaught

Я пытаюсь обобщить обработку ошибок для HTTP-запросов и всегда отвечаю фактическим HTTP-кодом ошибки и соответствующим сообщением.

Вот моя проблема: в моем обработчике, который расширяет SimpleChannelUpstreamHandler, exceptionCaught запускается, когда исключение выдается в любом месте стека. Это хорошо. Плохо то, что когда я пытаюсь написать ответ клиенту с соответствующим HTTP-кодом и ответом, запись вызывает исключение, а затем программа входит в бесконечный цикл с вызовом exceptionCaught снова и снова.

Это должно быть обычное задание. Как я могу сделать это правильно?

@Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent event)
        throws Exception {

    try{
        logger.error("Error in handling call: ", event.getCause());
        HttpResponse httpResponse = buildHttpResponseObject(UNAUTHORIZED, new StringBuilder("Test"), false, null);

        // Write the response.
        // for some reason calling this next line causes an infinite loop of exceptionCaught, even with the
        // catch below.  No idea why.  Still investigating.  In the meantime, we don't have custom error code responses. 
        ChannelFuture future = event.getChannel().write(httpResponse);

        // Close the connection after the write operation is done, even if it's a keep-alive.
        future.addListener(ChannelFutureListener.CLOSE);
    }
    catch(Exception t){            
        logger.error("Unable to customize error response. ", t);
        event.getChannel().close();

    }
}

Вот исключения:

38161 [New I/O server worker #1-1] ERROR nettytests.http.snoop.HttpSnoopServerHandler - Error in handling call: 
javax.net.ssl.SSLHandshakeException: null cert chain
    at sun.security.ssl.Handshaker.checkThrown(Handshaker.java:1364)
    at sun.security.ssl.SSLEngineImpl.checkTaskThrown(SSLEngineImpl.java:513)
    at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:790)
    at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:758)
    at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
    at org.jboss.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:931)
    at org.jboss.netty.handler.ssl.SslHandler.decode(SslHandler.java:649)
    at org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode(FrameDecoder.java:288)
    at org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:207)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:343)
    at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:274)
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:194)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)
Caused by: javax.net.ssl.SSLHandshakeException: null cert chain
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1639)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:278)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:266)
    at sun.security.ssl.ServerHandshaker.clientCertificate(ServerHandshaker.java:1627)
    at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:176)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:868)
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:808)
    at sun.security.ssl.Handshaker$1.run(Handshaker.java:806)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.security.ssl.Handshaker$DelegatedTask.run(Handshaker.java:1301)
    at org.jboss.netty.handler.ssl.SslHandler$3.run(SslHandler.java:1060)
    at org.jboss.netty.handler.ssl.ImmediateExecutor.execute(ImmediateExecutor.java:31)
    at org.jboss.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1057)
    at org.jboss.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:947)
    ... 11 more
38177 [New I/O server worker #1-1] ERROR nettytests.http.snoop.HttpSnoopServerHandler - Error in handling call: 
java.lang.IllegalStateException: cannot send more responses than requests
    at org.jboss.netty.handler.codec.http.HttpContentEncoder.writeRequested(HttpContentEncoder.java:104)
    at org.jboss.netty.channel.Channels.write(Channels.java:605)
    at org.jboss.netty.channel.Channels.write(Channels.java:572)
    at org.jboss.netty.channel.AbstractChannel.write(AbstractChannel.java:245)
    at nettytests.http.snoop.HttpSnoopServerHandler.exceptionCaught(HttpSnoopServerHandler.java:201)
    at nettytests.logger.RequestAuditLogger.handleUpstream(RequestAuditLogger.java:32)
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.exceptionCaught(ReplayingDecoder.java:456)
    at org.jboss.netty.handler.ssl.SslHandler.exceptionCaught(SslHandler.java:554)
    at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:426)
    at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractChannelSink.java:47)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:343)
    at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:274)
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:194)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)
38177 [New I/O server worker #1-1] ERROR nettytests.http.snoop.HttpSnoopServerHandler - Error in handling call: 
java.lang.IllegalStateException: cannot send more responses than requests
    at org.jboss.netty.handler.codec.http.HttpContentEncoder.writeRequested(HttpContentEncoder.java:104)
    at org.jboss.netty.channel.Channels.write(Channels.java:605)
    at org.jboss.netty.channel.Channels.write(Channels.java:572)
    at org.jboss.netty.channel.AbstractChannel.write(AbstractChannel.java:245)
    at nettytests.http.snoop.HttpSnoopServerHandler.exceptionCaught(HttpSnoopServerHandler.java:201)
    at nettytests.logger.RequestAuditLogger.handleUpstream(RequestAuditLogger.java:32)
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.exceptionCaught(ReplayingDecoder.java:456)
    at org.jboss.netty.handler.ssl.SslHandler.exceptionCaught(SslHandler.java:554)
    at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:426)
    at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractChannelSink.java:47)
    at org.jboss.netty.channel.Channels.write(Channels.java:605)
    at org.jboss.netty.channel.Channels.write(Channels.java:572)
    at org.jboss.netty.channel.AbstractChannel.write(AbstractChannel.java:245)
    at nettytests.http.snoop.HttpSnoopServerHandler.exceptionCaught(HttpSnoopServerHandler.java:201)
    at nettytests.logger.RequestAuditLogger.handleUpstream(RequestAuditLogger.java:32)
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.exceptionCaught(ReplayingDecoder.java:456)
    at org.jboss.netty.handler.ssl.SslHandler.exceptionCaught(SslHandler.java:554)
    at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:426)
    at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractChannelSink.java:47)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:343)
    at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:274)
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:194)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)
38224 [New I/O server worker #1-1] ERROR nettytests.http.snoop.HttpSnoopServerHandler - Error in handling call: 
java.lang.IllegalStateException: cannot send more responses than requests
    at org.jboss.netty.handler.codec.http.HttpContentEncoder.writeRequested(HttpContentEncoder.java:104)
    at org.jboss.netty.channel.Channels.write(Channels.java:605)
    at org.jboss.netty.channel.Channels.write(Channels.java:572)
    at org.jboss.netty.channel.AbstractChannel.write(AbstractChannel.java:245)
    at nettytests.http.snoop.HttpSnoopServerHandler.exceptionCaught(HttpSnoopServerHandler.java:201)
    at nettytests.logger.RequestAuditLogger.handleUpstream(RequestAuditLogger.java:32)
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.exceptionCaught(ReplayingDecoder.java:456)
    at org.jboss.netty.handler.ssl.SslHandler.exceptionCaught(SslHandler.java:554)
    at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:426)
    at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractChannelSink.java:47)
    at org.jboss.netty.channel.Channels.write(Channels.java:605)
    at org.jboss.netty.channel.Channels.write(Channels.java:572)
    at org.jboss.netty.channel.AbstractChannel.write(AbstractChannel.java:245)
    at nettytests.http.snoop.HttpSnoopServerHandler.exceptionCaught(HttpSnoopServerHandler.java:201)
    at nettytests.logger.RequestAuditLogger.handleUpstream(RequestAuditLogger.java:32)
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.exceptionCaught(ReplayingDecoder.java:456)
    at org.jboss.netty.handler.ssl.SslHandler.exceptionCaught(SslHandler.java:554)
    at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:426)
    at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractChannelSink.java:47)
    at org.jboss.netty.channel.Channels.write(Channels.java:605)
    at org.jboss.netty.channel.Channels.write(Channels.java:572)
    at org.jboss.netty.channel.AbstractChannel.write(AbstractChannel.java:245)
    at nettytests.http.snoop.HttpSnoopServerHandler.exceptionCaught(HttpSnoopServerHandler.java:201)
    at nettytests.logger.RequestAuditLogger.handleUpstream(RequestAuditLogger.java:32)
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.exceptionCaught(ReplayingDecoder.java:456)
    at org.jboss.netty.handler.ssl.SslHandler.exceptionCaught(SslHandler.java:554)
    at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:426)
    at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractChannelSink.java:47)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:343)
    at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:274)
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:194)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)
38255 [New I/O server worker #1-1] ERROR nettytests.http.snoop.HttpSnoopServerHandler - Error in handling call: 
java.lang.IllegalStateException: cannot send more responses than requests
    at org.jboss.netty.handler.codec.http.HttpContentEncoder.writeRequested(HttpContentEncoder.java:104)
    at org.jboss.netty.channel.Channels.write(Channels.java:605)
    at org.jboss.netty.channel.Channels.write(Channels.java:572)
    at org.jboss.netty.channel.AbstractChannel.write(AbstractChannel.java:245)
    at nettytests.http.snoop.HttpSnoopServerHandler.exceptionCaught(HttpSnoopServerHandler.java:201)
    at nettytests.logger.RequestAuditLogger.handleUpstream(RequestAuditLogger.java:32)
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.exceptionCaught(ReplayingDecoder.java:456)
    at org.jboss.netty.handler.ssl.SslHandler.exceptionCaught(SslHandler.java:554)
    at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:426)
    at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractChannelSink.java:47)
    at org.jboss.netty.channel.Channels.write(Channels.java:605)
    at org.jboss.netty.channel.Channels.write(Channels.java:572)
    at org.jboss.netty.channel.AbstractChannel.write(AbstractChannel.java:245)
    at nettytests.http.snoop.HttpSnoopServerHandler.exceptionCaught(HttpSnoopServerHandler.java:201)
    at nettytests.logger.RequestAuditLogger.handleUpstream(RequestAuditLogger.java:32)
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.exceptionCaught(ReplayingDecoder.java:456)
    at org.jboss.netty.handler.ssl.SslHandler.exceptionCaught(SslHandler.java:554)
    at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:426)
    at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractChannelSink.java:47)
    at org.jboss.netty.channel.Channels.write(Channels.java:605)
    at org.jboss.netty.channel.Channels.write(Channels.java:572)
    at org.jboss.netty.channel.AbstractChannel.write(AbstractChannel.java:245)
    at nettytests.http.snoop.HttpSnoopServerHandler.exceptionCaught(HttpSnoopServerHandler.java:201)
    at nettytests.logger.RequestAuditLogger.handleUpstream(RequestAuditLogger.java:32)
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.exceptionCaught(ReplayingDecoder.java:456)
    at org.jboss.netty.handler.ssl.SslHandler.exceptionCaught(SslHandler.java:554)
    at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:426)
    at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractChannelSink.java:47)
    at org.jboss.netty.channel.Channels.write(Channels.java:605)
    at org.jboss.netty.channel.Channels.write(Channels.java:572)
    at org.jboss.netty.channel.AbstractChannel.write(AbstractChannel.java:245)
    at nettytests.http.snoop.HttpSnoopServerHandler.exceptionCaught(HttpSnoopServerHandler.java:201)
    at nettytests.logger.RequestAuditLogger.handleUpstream(RequestAuditLogger.java:32)
    at org.jboss.netty.handler.codec.replay.ReplayingDecoder.exceptionCaught(ReplayingDecoder.java:456)
    at org.jboss.netty.handler.ssl.SslHandler.exceptionCaught(SslHandler.java:554)
    at org.jboss.netty.channel.Channels.fireExceptionCaught(Channels.java:426)
    at org.jboss.netty.channel.AbstractChannelSink.exceptionCaught(AbstractChannelSink.java:47)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:268)
    at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:255)
    at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:343)
    at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:274)
    at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:194)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

... повторять до бесконечности.


person MeowCode    schedule 06.03.2012    source источник


Ответы (1)


Бесконечный цикл - это плохо. Я заметил, что вы вызываете Channel.close() в блоке finally. В большинстве случаев это происходит до того, как вы сможете что-то написать в канал. Вы должны использовать

future.addListener (ChannelFutureListener.CLOSE);

Закрывать канал после того, как вы что-то написали. Это должно даже вызвать исключение

person Norman Maurer    schedule 07.03.2012
comment
Я ценю, что вы нашли время, чтобы изучить проблему. Да, бесконечный цикл — это очень плохо. Итак, я изменил код, и теперь он делает именно то, что вы сказали. Все та же проблема. Есть предположения? Новый код опубликован в измененном вопросе, поскольку комментарии плохо форматируют код. - person MeowCode; 07.03.2012
comment
Проблема в том, что вы пытаетесь написать клиенту сообщение об ошибке после того, как оно уже было написано. И это не разрешено, поскольку http поддерживает только отношение 1-к-1. - person Norman Maurer; 08.03.2012
comment
Кажется, теперь я вижу! Итак, сообщение SslHandler exceptionCaught уже отправляет ответ клиенту, а затем я тоже пытаюсь это сделать. Хм. Думаю, я могу переопределить SslHandler, чтобы он вел себя немного иначе. - person MeowCode; 08.03.2012