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;
Code: Select all
tomcat:
connection-timeout: 900000 (default is 60000).
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:

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
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
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)));
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)
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.
 Mobile version
 Mobile version