2014-11-05 9 views
9

Ich verwende Jersey 2.13 in meiner Webanwendung zum Abrufen von Daten async. Es gibt einige Fälle, in denen Anforderungen einige Zeit benötigen (i.E., wenn komplexe Berichte ausgeführt werden), bis ihre Antwort an den Client zurückkehrt.ClientAbortException bei der Verwendung von Jersey 2.13

Wenn der Client nicht auf die asynchrone Antwort wartet (verlässt die Seite, schließt den Browser usw.), wird eine ClientAbortException ausgelöst. Dieses Verhalten ist wie erwartet, aber es überflutet meine Protokolldateien mit Stack-Ablaufverfolgungen, da jede einzelne asynchrone Anforderung, die abgebrochen wird, bevor die Antwort zurückgibt, eine Stapelüberwachung druckt.

Der Stack-Trace sieht wie folgt aus:

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 

ich auch das Jersey ExceptionMapper mit mehreren Ausnahmen abzubilden, aber das hat weder die Arbeit für

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

noch für

org.apache.catalina.connector.ClientAbortException 

Gibt es eine Möglichkeit, diese Ausnahme abzufangen und das Drucken des gesamten Stack-Trace zu verhindern?

EDIT:

immer noch nach einer Antwort suchen ...

+0

Ich bin auch sehr daran interessiert. Ich bekomme nicht nur einen Jersey Stacktrace, aber es wirft es zum Container (Tomcat) und ich bekomme einen Container Stacktrace – ChrisO

+0

Ich kann versuchen, Ihnen zu helfen. Können Sie den Endpunktcode/Clientcode teilen, um den Fehler zu reproduzieren? Vielen Dank. – jeorfevre

Antwort

0

Nachdem in den Jersey Grub Coding ich den einzigen Weg, dies durch das Jersey internen Logger deaktivieren ist die Archivierung herausgefunden hat. Dies kann in der Klasse erfolgen, die ResourceConfig erweitert.

@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

Ich arbeitete diese Ausgabe um durch eine niedrige Priorität WriterInterceptor hinzufügen, die während Antworten Schreiben geworfen Ausnahmen erkennen und ignoriert. Wenn Sie auf Tomcat laufen und eine Abhängigkeit von Tomcat-Klassen nicht stören, können Sie org.apache.catalina.connector.ClientAbortException anstatt setOutputStream aufrufen, wodurch die Notwendigkeit für die beiden geschachtelten Klassen (und die Abhängigkeit von org.apache.commons.io.output.ProxyOutputStream, die auch mit eine benutzerdefinierte OutputStream Unterklasse).

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); 
     } 
    } 
} 
Verwandte Themen