Spring+Tomcat8.5环境下ServletOutputStream写入PDF文件异常求助
Hey there, let's break down this problem step by step—since most users are working fine but a subset is hitting that ERR_EMPTY_RESPONSE after 3 minutes of lag, it's likely a scenario-specific issue rather than a global configuration bug. Here are the key areas to investigate:
First, let's rule out Tomcat's connection and async timeouts, since the 3-minute window lines up with common timeout thresholds:
- Check your
server.xml'sConnectorconfiguration for these parameters:
The<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" keepAliveTimeout="60000" asyncTimeout="180000" />asyncTimeout(set to 180s here) is a big one if your PDF generation uses async servlets—if the task takes longer than this, Tomcat will kill the connection, leading to an empty response. - Also, verify if Tomcat's
connectionTimeoutis set too low for large PDF generation tasks, though 20s is the default and your users are waiting 3 minutes, so this is less likely unless there's queueing.
Since only some users are affected, the problem might be tied to specific data sets they're requesting:
- Slow Database Queries: Some users might be triggering queries that pull way more data than usual. Enable your database's slow query log to catch these, then check for missing indexes, N+1 query issues in your Spring Data/JPA code, or unoptimized joins.
- PDF Rendering Resource Limits: Generating large or complex PDFs (with lots of images, tables, or dynamic content) can hog CPU and memory.
- Use tools like
jstatorjconsoleto monitor your Tomcat JVM's memory usage—frequent Full GC pauses can freeze responses until the JVM recovers. - Double-check your PDF library (iText, PDFBox, etc.) code: make sure you're closing all resources (like
DocumentorInputStreaminstances) with try-with-resources blocks to avoid leaks.
- Use tools like
In Spring apps, improper handling of ServletOutputStream is a common culprit for empty responses:
- Missing Response Headers: Without setting
Content-Length, Tomcat uses chunked transfer encoding, which some older browsers or proxies struggle with during long downloads. Add these headers before writing to the stream:response.setContentType("application/pdf"); response.setContentLengthLong(calculatedPdfSize); // Calculate this before generating if possible response.setHeader("Content-Disposition", "attachment; filename=\"generated-document.pdf\""); - Unclosed/Unflushed Streams: If you forget to call
out.flush()or don't properly close the stream (especially in error cases), Tomcat might hold the connection open until it times out. Use try-with-resources to guarantee cleanup:try (ServletOutputStream out = response.getOutputStream()) { // Generate and write your PDF to out out.flush(); } catch (Exception e) { // Make sure to send an error response instead of leaving the connection hanging response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to generate PDF"); } - Async Task Misconfiguration: If you're using
@Asyncfor PDF generation, ensure you're properly wiring the task to complete and send the response—if the async task hangs or fails to notify the servlet, Tomcat will kill the connection afterasyncTimeout.
Sometimes the issue isn't on your server, but in the user's network:
- Ask affected users if they're behind an enterprise proxy, VPN, or firewall—these often have strict timeout rules for long-running requests.
- Test adding these response headers to help proxies handle the download better:
response.setHeader("Connection", "keep-alive"); response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
If your Tomcat thread pool is exhausted, new requests will queue up until threads become available—leading to long delays and eventual timeouts:
- Check your
server.xml'sExecutorconfiguration:
If<Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="200" minSpareThreads="25" queueCapacity="100"/>maxThreadsis too low orqueueCapacityis filled, requests will wait indefinitely. Monitor Tomcat's thread usage via the manager app to see if this is happening.
内容的提问来源于stack exchange,提问作者DFL

