Tomcat随机返回content-length为0导致PDF.js加载大PDF报错问题求助
核心问题排查方向
- 优先排查Web容器响应缓冲配置问题:Tomcat等默认响应缓冲区为8KB以内,小文件可一次性写入缓冲区,容器能自动计算Content-Length正常返回;大文件写入时缓冲区提前写满触发flush,你当前代码未显式声明Content-Length也未禁用缓冲,部分场景下容器会误判响应无有效数据,返回
content-length: 0,直接触发PDF.js的"Stream must have data"报错。 - 排查异常处理逻辑缺陷:若
service.getDocument(docId)、大文件流读取过程中偶发超时、IO异常,抛出的RuntimeException被全局异常处理器捕获后清空了响应流,也会导致返回空响应。 - 排查反向代理/网关配置:若服务前部署Nginx等网关,需确认是否配置了单请求响应大小限制、传输超时时间过短,大文件传输触发网关截断响应,直接返回空内容。
修复代码参考
@GetMapping(value = { "/view/{id}" }, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) public void downloadFile(@PathVariable("id") DiskFileId docId, HttpServletResponse response) throws IOException { StorageDocumentDTO document = null; try { document = service.getDocument(docId); if(document == null) { response.setStatus(HttpServletResponse.SC_NOT_FOUND); return; } File pdfFile = document.getDocumentPath().toFile(); // 显式设置Content-Length,避免容器自动计算错误 response.setContentLengthLong(pdfFile.length()); response.setContentType(document.getMimeType()); // 禁用响应缓冲,大文件直接走chunked传输 response.setBufferSize(0); // 用try-with-resources自动关闭文件流,避免资源泄漏 try (FileInputStream fis = new FileInputStream(pdfFile)) { IOUtils.copy(fis, response.getOutputStream()); response.getOutputStream().flush(); } } catch (Exception e) { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // 异常时主动写响应,避免全局异常处理器覆盖清空响应流 try (PrintWriter writer = response.getWriter()) { writer.write("Document load failed"); } throw new RuntimeException("Document not found", e); } }
验证步骤
- 直连应用服务测试大文件下载,排除网关层截断问题
- 给文件读取、流复制步骤增加日志,打印文件大小、实际传输字节数,确认服务端是否完整读取并传输了文件内容
- 临时将容器响应缓冲区调整为16MB,测试大文件加载是否正常,确认是否为缓冲区溢出导致的问题
内容的提问来源于stack exchange,提问作者msmani
相关产品推荐
相关产品推荐

