SpringBoot MVC实现文件下载无报错但无法执行,求排查原因
SpringBoot MVC文件下载无报错但无法执行的排查
我用SpringBoot MVC实现文件下载功能,程序运行没报错,但下载操作就是不生效。已经确认文件路径、文件名等信息都正确,想知道问题出在哪。
@RestController public class Controller { @PostMapping("/fileDownload") public void fileDownload(@RequestBody BoardFileDTO dto,HttpServletRequest request,HttpServletResponse response) throws UnsupportedEncodingException { //File contains all stored paths, names, and extensions Path fileNamePath = Paths.get(Directory + dto.getFile_save_name()).toAbsolutePath(); String filename = dto.getFile_save_name(); //The name of the saved file String downname = dto.getFile_name(); //The name of the file to be saved if (filename == null || "".equals(filename)) { filename = downname; } try { String browser = request.getHeader("User-Agent"); //File Encoding if (browser.contains("MSIE") || browser.contains("Trident") || browser.contains("Chrome")) { filename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20"); } else { filename = new String(filename.getBytes("UTF-8"), "ISO-8859-1"); } } catch (UnsupportedEncodingException ex) { System.out.println("UnsupportedEncodingException"); } System.out.println(fileNamePath); File file1 = new File(fileNamePath.toString()); if (!file1.exists()) { return ; } // Specifying a File response.setContentType("application/octer-stream"); response.setHeader("Content-Transfer-Encoding", "binary;"); response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\""); try { OutputStream os = response.getOutputStream(); FileInputStream fis = new FileInputStream(fileNamePath.toString()); int ncount = 0; byte[] bytes = new byte[512]; while ((ncount = fis.read(bytes)) != -1 ) { os.write(bytes, 0, ncount); } fis.close(); os.close(); } catch (FileNotFoundException ex) { System.out.println("FileNotFoundException"); } catch (IOException ex) { System.out.println("IOException"); } } }
核心问题分析
- 请求方式不匹配:当前用
@PostMapping接收请求,但浏览器触发下载一般是GET请求;如果是前端AJAX发起POST,默认不会处理响应的二进制流,自然不会弹出下载窗口。 - ContentType拼写错误:代码里写的
application/octer-stream是错的,正确应为application/octet-stream,这个错误会导致浏览器无法识别响应类型,不触发下载逻辑。 - 响应头格式问题:
Content-Transfer-Encoding头里多了分号,规范写法是binary而非binary;,部分浏览器可能因此无法正确解析响应。 - 流处理不规范:直接调用
close()关闭流,未确保数据全部刷新到客户端;且未使用try-with-resources语法,存在资源泄漏风险,可能导致响应不完整。 - 缺失文件长度头:没有设置
Content-Length,浏览器无法判断文件是否传输完成,可能中断下载流程。
修正后的代码示例
@RestController public class Controller { @GetMapping("/fileDownload") // 改为GET请求,适配浏览器下载逻辑 public void fileDownload(@RequestParam BoardFileDTO dto, HttpServletRequest request, HttpServletResponse response) { Path fileNamePath = Paths.get(Directory + dto.getFile_save_name()).toAbsolutePath(); String filename = dto.getFile_save_name(); String downname = dto.getFile_name(); if (filename == null || filename.isBlank()) { filename = downname; } // 文件名编码适配不同浏览器 try { String browser = request.getHeader("User-Agent"); if (browser.contains("MSIE") || browser.contains("Trident") || browser.contains("Chrome")) { filename = URLEncoder.encode(filename, "UTF-8").replaceAll("\\+", "%20"); } else { filename = new String(filename.getBytes("UTF-8"), "ISO-8859-1"); } } catch (UnsupportedEncodingException ex) { System.err.println("文件名编码失败:" + ex.getMessage()); } File targetFile = new File(fileNamePath.toString()); if (!targetFile.exists()) { response.setStatus(HttpServletResponse.SC_NOT_FOUND); return; } // 设置正确的响应头 response.setContentType("application/octet-stream"); response.setHeader("Content-Transfer-Encoding", "binary"); response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\""); response.setContentLength((int) targetFile.length()); // 添加文件长度信息 // 使用try-with-resources自动管理流,确保资源正确释放 try (FileInputStream fis = new FileInputStream(targetFile); OutputStream os = response.getOutputStream()) { byte[] buffer = new byte[4096]; // 增大缓冲区提升传输效率 int readLen; while ((readLen = fis.read(buffer)) != -1) { os.write(buffer, 0, readLen); } os.flush(); // 强制刷新输出流,确保所有数据发送到客户端 } catch (FileNotFoundException ex) { System.err.println("目标文件不存在:" + ex.getMessage()); response.setStatus(HttpServletResponse.SC_NOT_FOUND); } catch (IOException ex) { System.err.println("文件传输失败:" + ex.getMessage()); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } }
内容的提问来源于stack exchange,提问作者Dustin
相关产品推荐
相关产品推荐

