SocketTimeoutException beim Herunterladen großer Dateien. Dieses Verhalten ist bei verschiedenen Browsern inkonsistentJava

Java-Forum
Anonymous
 SocketTimeoutException beim Herunterladen großer Dateien. Dieses Verhalten ist bei verschiedenen Browsern inkonsistent

Post by Anonymous »

Beschreibung des Fehlers
Wenn ich Vaadin mit Spring-Boot verwende und versuche, eine Datei mit der DownloadHandler.fromInputStream-API herunterzuladen, wird der Download nach einiger Zeit unterbrochen.
Im Firefox-Browser wird er nach 30 Sekunden unterbrochen. Bei Chromium-basierten Browsern (Chrome und Brave ausprobiert) wird der Download unterbrochen, nachdem 1 GB Daten heruntergeladen wurden.
Die Anwendung wird als WAR-Datei auf einem Debian-Server hinter einem Nginx-Proxy bereitgestellt. Für den gesamten Nginx-Proxy ist das Timeout auf einen hohen Wert eingestellt, sodass aufgrund von Nginx kein Timeout auftritt:

Code: Select all

send_timeout 300;
proxy_connect_timeout 600;
proxy_send_timeout 600;
proxy_read_timeout 600;
Bezüglich der Tomcat- und Spring-Konfiguration habe ich versucht, hohe Werte für Timeouts oder unendliche Timeouts zu verwenden, aber sie haben keine Auswirkung:

Code: Select all

tomcat:
connection-timeout: 900000 (default is 60000).
Ich habe keine Standard-Timeout-Konfiguration des von mir verwendeten Stacks gefunden, die beim Herunterladen einer Datei zu einem Timeout von 30 Sekunden führen könnte. Darüber hinaus ist dieses Verhalten bei verschiedenen Browsertypen inkonsistent.
Ein Blick auf den Netzwerkinspektor in Firefox zeigt, dass der Anforderungsstatus 200 ist, aber nach 30 Sekunden erhält er NS_BINDING_ABORTED. Der Download wird vom Benutzer nicht abgebrochen. Ich habe auch versucht, die Standard-Timeouts in Firefox zu erhöhen, hatte aber keine Wirkung:
Image

Ich habe auch versucht, verschiedene Java-/Tomcat-Versionen zu verwenden.
Interessant ist auch, dass das Hochladen einer großen Datei mit der Upload-Komponente in Vaadin ohne Probleme verläuft. Das Problem tritt nur während des Downloads auf.
Vaadin Java-Code:

Code: Select all

hiddenDownloadAnchor.setHrefAndDownload(DownloadHandler.fromInputStream(
downloadEvent -> new DownloadResponse(
new FileInputStream(file),
name,
type,
length))); // hiddenDownloadAnchor is hidden Anchor component from Vaadin
Die Inhaltslänge ist korrekt eingestellt, auch beim MIME-Typ. Ich habe auch versucht, Null- oder -1-Werte zu verwenden, um eine unbekannte Größe oder einen automatisch entscheidenden Mime-Typ anzugeben, was keine Auswirkung hatte.
Wenn ich mir den Stack-Trace ansehe, wo die Ausnahme in Tomcat ausgelöst wird: NioSocketWrapper.doWrite(NioEndpoint.java:1410), kann ich sehen, dass es aus irgendeinem Grund eine Zeitüberschreitung gibt, aber wenn ich mir die Variable timeout im Debug anschaue, die abgerufen wird von getWriteTimeout(), ist länger als 30 Sekunden (sogar die Standardeinstellung ist 60), daher habe ich keine Ahnung, warum dies in Firefox regelmäßig nach 30 Sekunden und in Chromium-basierten Browsern nach dem Herunterladen von 1 GB geschieht (über 30 Sekunden: Herunterladen für etwa 5 Minuten).
Vollständiger Stack-Trace:

Code: Select all

org.apache.catalina.connector.ClientAbortException:  j a v a . n e t . S o c k e t T i m e o u t E x c e p t i o n < b r   / >                 a t   o r g . a p a c h e . c a t a l i n a . c o n n e c t o r . O u t p u t B u f f e r . r e a l W r i t e B y t e s ( O u t p u t B u f f e r . j a v a : 3 4 2 ) < b r   / >                 a t   o r g . a p a c h e . c a t a l i n a . c o n n e c t o r . O u t p u t B u f f e r . a p p e n d B y t e A r r a y ( O u t p u t B u f f e r . j a v a : 7 4 7 ) < b r   / >                 a t   o r g . a p a c h e . c a t a l i n a . c o n n e c t o r . O u t p u t B u f f e r . a p p e n d ( O u t p u t B u f f e r . j a v a : 6 7 5 ) < b r   / >                 a t   o r g . a p a c h e . c a t a l i n a . c o n n e c t o r . O u t p u t B u f f e r . w r i t e B y t e s ( O u t p u t B u f f e r . j a v a : 3 7 7 ) < b r   / >                 a t   o r g . a p a c h e . c a t a l i n a . c o n n e c t o r . O u t p u t B u f f e r . w r i t e ( O u t p u t B u f f e r . j a v a : 3 5 5 ) < b r   / >                 a t   o r g . a p a c h e . c a t a l i n a . c o n n e c t o r . C o y o t e O u t p u t S t r e a m . w r i t e ( C o y o t e O u t p u t S t r e a m . j a v a : 1 0 2 ) < b r   / >                 a t   c o m . v a a d i n . f l o w . s e r v e r . s t r e a m s . T r a n s f e r U t i l . t r a n s f e r ( T r a n s f e r U t i l . j a v a : 9 7 ) < b r   / >                 a t   c o m . v a a d i n . f l o w . s e r v e r . s t r e a m s . I n p u t S t r e a m D o w n l o a d H a n d l e r . h a n d l e D o w n l o a d R e q u e s t ( I n p u t S t r e a m D o w n l o a d H a n d l e r . j a v a : 1 0 1 ) < b r   / >                 a t   c o m . v a a d i n . f l o w . s e r v e r . s t r e a m s . D o w n l o a d H a n d l e r . h a n d l e R e q u e s t ( D o w n l o a d H a n d l e r . j a v a : 1 0 4 ) < b r   / >                 a t   c o m . v a a d i n . f l o w . s e r v e r . c o m m u n i c a t i o n . S t r e a m R e q u e s t H a n d l e r . c a l l E l e m e n t R e s o u r c e H a n d l e r ( S t r e a m R e q u e s t H a n d l e r . j a v a : 1 9 4 ) < b r   / >                 a t   c o m . v a a d i n . f l o w . s e r v e r . c o m m u n i c a t i o n . S t r e a m R e q u e s t H a n d l e r . h a n d l e R e q u e s t ( S t r e a m R e q u e s t H a n d l e r . j a v a : 1 1 9 ) < b r   / >                 a t   c o m . v a a d i n . f l o w . s e r v e r . V a a d i n S e r v i c e . h a n d l e R e q u e s t ( V a a d i n S e r v i c e . j a v a : 1 8 7 9 ) < b r   / >                 a t   c o m . v a a d i n . f l o w . s e r v e r . V a a d i n S e r v l e t . s e r v i c e ( V a a d i n S e r v l e t . j a v a : 3 9 8 ) < b r   / >                 a t   c o m . v a a d i n . f l o w . s p r i n g . S p r i n g S e r v l e t . s e r v i c e ( S p r i n g S e r v l e t . j a v a : 1 0 6 ) < b r   / >                 a t   j a k a r t a . s e r v l e t . h t t p . H t t p S e r v l e t . s e r v i c e ( H t t p S e r v l e t . j a v a : 6 5 8 ) < b r   / >                 a t   o r g . a p a c h e . c a t a l i n a . c o r e . A p p l i c a t i o n F i l t e r C h a i n . i n t e r n a l D o F i l t e r ( A p p l i c a t i o n F i l t e r C h a i n . j a v a : 1 9 5 ) < b r   / >                 a t   o r g . a p a c h e . c a t a l i n a . c o r e . A p p l i c a t i o n F i l t e r C h a i n . d o F i l t e r ( A p p l i c a t i o n F i l t e r C h a i n . j a v a : 1 4 0 ) < b r   / >                 a t   o r g . a p a c h e . c a t a l i n a . c o r e . A p p l i c a t i o n D i s p a t c h e r . i n v o k e ( A p p l i c a t i o n D i s p a t c h e r . j a v a : 6 1 2 ) < b r   / >                 a t   o r g . a p a c h e . c a t a l i n a . c o r e . A p p l i c a t i o n D i s p a t c h e r . p r o c e s s R e q u e s t ( A p p l i c a t i o n D i s p a t c h e r . j a v a : 3 9 4 ) < b r   / >                 a t   o r g . a p a c h e . c a t a l i n a . c o r e . A p p l i c a t i o n D i s p a t c h e r . d o F o r w a r d ( A p p l i c a t i o n D i s p a t c h e r . j a v a : 3 2 3 ) < b r   / >                 a t   o r g . a p a c h e . c a t a l i n a . c o r e . A p p l i c a t i o n D i s p a t c h e r . f o r w a r d ( A p p l i c a t i o n D i s p a t c h e r . j a v a : 2 6 8 ) < b r   / >                 a t   o r g . s p r i n g f r a m e w o r k . w e b . s e r v l e t . m v c . S e r v l e t F o r w a r d i n g C o n t r o l l e r . h a n d l e R e q u e s t I n t e r n a l ( S e r v l e t F o r w a r d i n g C o n t r o l l e r . j a v a : 1 4 2 ) < b r   / >                 a t   o r g . s p r i n g f r a m e w o r k . w e b . s e r v l e t . m v c . A b s t r a c t C o n t r o l l e r . h a n d l e R e q u e s t ( A b s t r a c t C o n t r o l l e r . j a v a : 1 7 8 )
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:51)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:124)
at org.springframework.boot.web.servlet.support.ErrorPageFilter$1.doFilterInternal(ErrorPageFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.springframework.boot.web.servlet.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:117)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:116)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:666)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:398)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:903)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1776)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:975)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:493)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
at java.base/java.lang.Thread.run(Thread.java:1474)
Caused by:  java.net.SocketTimeoutException
at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.doWrite(NioEndpoint.java:1410)
at org.apache.tomcat.util.net.SocketWrapperBase.doWrite(SocketWrapperBase.java:732)
at org.apache.tomcat.util.net.SocketWrapperBase.writeBlocking(SocketWrapperBase.java:572)
at org.apache.tomcat.util.net.SocketWrapperBase.write(SocketWrapperBase.java:520)
at org.apache.coyote.http11.Http11OutputBuffer$SocketOutputBuffer.doWrite(Http11OutputBuffer.java:548)
at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:111)
at org.apache.coyote.http11.Http11OutputBuffer.doWrite(Http11OutputBuffer.java:193)
at org.apache.coyote.Response.doWrite(Response.java:628)
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:330)
... 70 more
Erwartetes Verhalten
Das Herunterladen großer Dateien sollte ohne Probleme abgeschlossen werden und im Firefox-Browser sollte nach 30 Sekunden oder nach dem Herunterladen von 1 GB in Chromium-basierten Browsern keine Zeitüberschreitung auftreten.
Minimales reproduzierbares Beispiel
Fügen Sie eine Ansicht zu Vaadin mit einem Anker hinzu und starten Sie den Download einer großen Datei (über 1 GB):

Code: Select all

hiddenDownloadAnchor.setHrefAndDownload(DownloadHandler.fromInputStream(
downloadEvent -> new DownloadResponse(
new FileInputStream(file),
name,
type,
length)));
Anwendung ist Spring Boot mit Tomcat, bereitgestellt als War hinter Nginx-Proxy.
Versionen
  • Vaadin / Flow-Version: 24.9.3
  • Java-Version: 25/21
  • Browserversion: Firefox 145.0b6 oder Brave 1.83.120 (Chromium: 141.0.7390.122)
  • Anwendungsserver: Tomcat 10.1.48 (auch älter ausprobiert: 10.1.46)
BEARBEITEN: Untersuchungsaktualisierung
Ich bin auf dieses alte Nginx-Problem gestoßen und habe Folgendes zitiert:

Hallo, wir haben Nginx Version 1.6.2 bis Version 1.12.2 ausprobiert und haben ein
Problem bei der Verwendung als Proxy vor Artifactory. Downloads werden
bei 1 GB unterbrochen.
Dieses Verhalten hängt vom internen VLAN ab. In einem VLAN passiert dies immer
. In einem anderen VLAN passiert es nie. Dies ist größenbegrenzt, nicht
zeitlich begrenzt. Bei einigen Netzwerken stoppt es nach 30 Sekunden und bei einem
anderen langsamen Netzwerk stoppt es nach 13 Minuten.
Wir haben ein minimales Proxy-Setup mit Apache durchgeführt und das funktioniert mit allen
VLANs. Aus diesem Grund gehen wir davon aus, dass es etwas mit Nginx oder der
Kombination aus Nginx und dem TCP/IP-Stack von Linux zu tun hat.
In wireshark sehen wir „TCP Dup ACK“ auf der Clientseite, das an den Nginx
Server gesendet wird.
Wget schlägt fehl, wenn die Verbindung bei Byte 1083793011 geschlossen wird, fährt aber mit dem teilweisen Download fort Inhalt. Docker kann damit nicht umgehen und unsere
Kunden können keine Docker-Images mit Ebenen größer als 1 GB herunterladen.

Mit Vorschlag:

Die 1-GB-Grenze legt nahe, dass das Problem auf
​proxy_max_temp_file_size zurückzuführen ist. Standardmäßig ist es ein Gigabyte, und wenn das Limit erreicht ist, stoppt Nginx das Lesen vom Backend, bis alle festplattengepufferten Daten an den Client gesendet wurden. Dies wiederum kann zu
einem Sende-Timeout auf der Backend-Seite führen.
Bitte überprüfen Sie Nginx und Ihre Backend-Protokolle, um zu sehen, was hier passiert.
Wahrscheinlich gibt es so etwas wie „Upstream-Verbindung vorzeitig geschlossen“ im Nginx-Fehlerprotokoll und Sende-Timeouts in Ihren Backend-Protokollen. Alternativ prüfen Sie einfach, ob Proxy_max_temp_file_size 0; hilft
(Dadurch wird die Festplattenpufferung vollständig deaktiviert).
Wenn der obige Vorschlag zutrifft, sind die beiden möglichen Lösungen:
Proxy_max_temp_file_size anpassen. Erwägen Sie, den Grenzwert entweder über der Größe aller erwarteten Antworten oder so klein zu konfigurieren, dass Ihr Backend keine Zeitüberschreitung erfährt. Insbesondere Proxy_max_temp_file_size 0;
könnte eine gute Wahl sein, wenn große Dateien per Proxy weitergeleitet werden. Passen Sie die Zeitüberschreitungen Ihres Backends entsprechend an.

Das Ändern dieser Proxy_max_temp_file_size auf 0 hilft bei Downloads auf Chromium-basierten Browsern, aber dieses Problem bleibt unter Firefox bestehen.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post