You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 09:15:03