2014-11-05 7 views
9

Sto utilizzando Jersey 2.13 nella mia applicazione Web per il recupero dei dati asincroni. Vi sono alcuni casi in cui le richieste richiedono del tempo (ad es. Quando si eseguono report complessi) finché la loro risposta non ritorna al client.ClientAbortException quando si utilizza Jersey 2.13

Quando il client non attende la risposta asincrona (lascia la pagina, chiude il browser, ecc.), Viene lanciata un'eccezione ClientAbortException. Questo comportamento è come previsto, ma è inondando i miei file di registro con tracce di stack perché ogni singola richiesta asincrona che viene annullata prima che la risposta ritorni, stampa una traccia dello stack.

L'analisi dello stack si presenta così:

Oct 15, 2014 2:25:23 PM org.glassfish.jersey.server.ServerRuntime$Responder writeResponse 
SEVERE: An I/O error has occurred while writing a response message entity to the container output stream. 
org.glassfish.jersey.server.internal.process.MappableException: ClientAbortException: java.io.IOException 
       at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:91) 
       at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162) 
       at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1154) 
       at org.glassfish.jersey.server.ServerRuntime$Responder.writeResponse(ServerRuntime.java:621) 
       at org.glassfish.jersey.server.ServerRuntime$Responder.processResponse(ServerRuntime.java:377) 
       at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:367) 
       at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:274) 
       at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271) 
       at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267) 
       at org.glassfish.jersey.internal.Errors.process(Errors.java:315) 
       at org.glassfish.jersey.internal.Errors.process(Errors.java:297) 
       at org.glassfish.jersey.internal.Errors.process(Errors.java:267) 
       at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:297) 
       at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:254) 
       at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1030) 
       at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:373) 
       at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:381) 
       at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:344) 
       at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:221) 
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) 
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 
       at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) 
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) 
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) 
       at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) 
       at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) 
       at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) 
       at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) 
       at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) 
       at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953) 
       at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) 
       at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:409) 
       at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1044) 
       at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) 
       at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2441) 
       at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2430) 
       at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) 
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) 
       at java.lang.Thread.run(Unknown Source) 
Caused by: ClientAbortException: java.io.IOException 
       at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:413) 
       at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:480) 
       at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:366) 
       at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:438) 
       at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:426) 
       at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:91) 
       at org.glassfish.jersey.servlet.internal.ResponseWriter$NonCloseableOutputStreamWrapper.write(ResponseWriter.java:298) 
       at org.glassfish.jersey.message.internal.CommittingOutputStream.write(CommittingOutputStream.java:229) 
       at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$UnCloseableOutputStream.write(WriterInterceptorExecutor.java:299) 
       at com.fasterxml.jackson.core.json.UTF8JsonGenerator._flushBuffer(UTF8JsonGenerator.java:1862) 
       at com.fasterxml.jackson.core.json.UTF8JsonGenerator.close(UTF8JsonGenerator.java:1087) 
       at com.fasterxml.jackson.jaxrs.base.ProviderBase.writeTo(ProviderBase.java:637) 
       at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:265) 
       at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:250) 
       at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162) 
       at org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor.aroundWriteTo(JsonWithPaddingInterceptor.java:106) 
       at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:162) 
       at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:85) 
       ... 38 more 
Caused by: java.io.IOException 
       at org.apache.coyote.http11.InternalAprOutputBuffer.flushBuffer(InternalAprOutputBuffer.java:205) 
       at org.apache.coyote.http11.InternalAprOutputBuffer.access$100(InternalAprOutputBuffer.java:37) 
       at org.apache.coyote.http11.InternalAprOutputBuffer$SocketOutputBuffer.doWrite(InternalAprOutputBuffer.java:235) 
       at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:117) 
       at org.apache.coyote.http11.AbstractOutputBuffer.doWrite(AbstractOutputBuffer.java:192) 
       at org.apache.coyote.Response.doWrite(Response.java:517) 
       at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:408) 
       ... 55 more 

Sto anche utilizzando il Jersey ExceptionMapper per mappare diverse eccezioni ma questo non lavoro per

org.glassfish.jersey.server.internal.process.MappableException 

nè per

org.apache.catalina.connector.ClientAbortException 

Esiste un modo per intercettare questa eccezione e impedire la stampa dell'intera traccia dello stack?

EDIT:

Ancora alla ricerca di una risposta ...

+0

Sono anche molto interessato a questo. Non solo ottengo uno stacktrace Jersey, ma lo butto al contenitore (tomcat) e ottengo un container stacktrace – ChrisO

+0

Posso provare ad aiutarti. Puoi condividere il codice del codice dell'endpoint/codice client per riprodurre il bug. Grazie. – jeorfevre

risposta

0

Dopo aver scavato nel Jersey Coding ho scoperto il l'unico modo per archiviare questo è disattivando il Logger interno Jersey. Questo può essere fatto nella classe che estende ResourceConfig.

@ApplicationPath("api") 
public class Application extends ResourceConfig { 

    private final static Logger ORG_GLASSFISH_JERSEY_LOGGER = Logger 
      .getLogger("org.glassfish.jersey"); 
    static { 
     ORG_GLASSFISH_JERSEY_LOGGER.setLevel(Level.OFF); 
    } 
} 
0

ho lavorato intorno a questo problema aggiungendo una bassa priorità WriterInterceptor che rileva e ignora le eccezioni sollevate durante la scrittura risposte. Se stai lavorando su Tomcat e non ti preoccupare di una dipendenza dalle classi Tomcat, potresti usare org.apache.catalina.connector.ClientAbortException piuttosto chiamando setOutputStream, che rimuoverebbe la necessità per le due classi nidificate (e la dipendenza da org.apache.commons.io.output.ProxyOutputStream, che potrebbe facilmente essere evitata anche con una sottoclasse personalizzata OutputStream invece).

import java.io.IOException; 
import java.io.OutputStream; 

import javax.annotation.Priority; 
import javax.ws.rs.ext.Provider; 
import javax.ws.rs.ext.WriterInterceptor; 
import javax.ws.rs.ext.WriterInterceptorContext; 

import org.apache.commons.io.output.ProxyOutputStream; 

/** 
* Ignore exceptions when writing a response, which almost always means the 
* client disconnected before reading the full response. 
*/ 
@Provider 
@Priority(1) 
public class ClientAbortExceptionWriterInterceptor implements WriterInterceptor { 
    @Override 
    public void aroundWriteTo(WriterInterceptorContext context) throws IOException { 
     context.setOutputStream(new ClientAbortExceptionOutputStream(context.getOutputStream())); 
     try { 
      context.proceed(); 
     } catch (Throwable t) { 
      for (Throwable cause = t; cause != null; cause = cause.getCause()) { 
       if (cause instanceof ClientAbortException) { 
        return; 
       } 
      } 
      throw t; 
     } 
    } 

    private static class ClientAbortExceptionOutputStream extends ProxyOutputStream { 
     public ClientAbortExceptionOutputStream(OutputStream out) { 
      super(out); 
     } 

     @Override 
     protected void handleIOException(IOException e) throws IOException { 
      throw new ClientAbortException(e); 
     } 
    } 

    @SuppressWarnings("serial") 
    private static class ClientAbortException extends IOException { 
     public ClientAbortException(IOException e) { 
      super(e); 
     } 
    } 
} 
Problemi correlati