在Spring Boot中如何将InputStream以文件形式返回?
Spring Boot 中返回JSch远程文件InputStream为下载文件的实现方案
以下是可直接运行的完整实现代码:
import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.JSch; import com.jcraft.jsch.Session; import java.io.InputStream; import java.net.URLEncoder; @RestController @RequestMapping("/sftp") public class SftpDownloadController { @GetMapping("/download/{fileName}") public ResponseEntity<InputStreamResource> downloadFile(@PathVariable String fileName) throws Exception { // 1. 建立JSch SSH连接,可替换为自身项目封装的JSch连接工具类/连接池获取逻辑 JSch jsch = new JSch(); Session session = jsch.getSession("SSH用户名", "远程服务器地址", 22); session.setPassword("SSH密码"); // 生产环境建议配置主机密钥校验规则,避免直接关闭校验 session.setConfig("StrictHostKeyChecking", "no"); session.connect(30000); // 30秒连接超时 // 2. 打开SFTP通道获取目标文件输入流 ChannelSftp sftpChannel = (ChannelSftp) session.openChannel("sftp"); sftpChannel.connect(10000); String remoteFullPath = "/remote/file/dir/" + fileName; // 替换为实际远程文件路径 InputStream fileInputStream = sftpChannel.get(remoteFullPath); // 3. 配置下载响应头 HttpHeaders responseHeaders = new HttpHeaders(); // 触发浏览器下载,中文文件名编码避免乱码 responseHeaders.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8")); responseHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM); // 可选:提前获取文件大小设置Content-Length头,优化下载进度显示 // long fileSize = sftpChannel.lstat(remoteFullPath).getSize(); // responseHeaders.setContentLength(fileSize); // 4. 包装输入流,绑定资源释放逻辑 InputStreamResource resource = new InputStreamResource(fileInputStream) { // Spring写入响应完成后会自动调用该方法释放资源 @Override public void close() throws Exception { super.close(); // 关闭SFTP通道和SSH会话,若使用连接池则改为归还连接到池 if (sftpChannel.isConnected()) { sftpChannel.disconnect(); } if (session.isConnected()) { session.disconnect(); } } }; return new ResponseEntity<>(resource, responseHeaders, HttpStatus.OK); } }
常见实现失败排查点
- 提前关闭资源:不要在return语句前手动关闭InputStream、SFTP通道或SSH会话,需等待Spring完成响应写入后统一释放,否则会出现流已关闭的报错
- 响应头配置错误:未设置
Content-Disposition: attachment会导致浏览器直接解析文件内容而非触发下载 - 文件名乱码:中文文件名必须经过UTF-8编码,否则部分浏览器会显示乱码
- 资源泄漏:未同步释放SFTP通道和SSH会话会导致连接堆积,最终服务无法建立新的SSH连接
- 连接超时:大文件下载场景需调整JSch会话超时时间,避免下载过程中连接被强制断开
内容的提问来源于stack exchange,提问作者MauriRamone
相关产品推荐
相关产品推荐

