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

如何通过Ajax POST处理Spring Boot Controller的InputStream响应并生成压缩文件

解决Spring Boot通过Ajax下载InputStream生成的压缩文件问题

首先得说下你当前代码里的几个关键问题,先把这些坑填上,再给你完整的解决方案:

一、修正后端Controller代码

你的原Controller有两个致命问题:

  1. 你在返回InputStream之前就调用了inputStream.close(),这会导致返回的流已经被关闭,前端根本拿不到有效数据;
  2. 使用@ResponseBody返回InputStream不是正确处理二进制文件的方式,应该直接通过HttpServletResponse输出流写入文件内容,同时设置正确的响应头让浏览器识别这是一个下载文件。

修正后的Controller代码:

@RequestMapping(value = "/test", method = RequestMethod.POST, headers="Accept=application/json")
public void downloadFile(@RequestBody Person person, HttpServletResponse response) throws Exception {
    File zipFile = FILE.getAbsoluteFile(); // 假设这是你的目标压缩文件
    try (InputStream inputStream = new FileInputStream(zipFile)) {
        // 设置响应头,告诉浏览器这是一个需要下载的zip文件
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment; filename=\"download.zip\"");
        response.setContentLength((int) zipFile.length());
        
        // 将输入流写入响应输出流
        OutputStream outputStream = response.getOutputStream();
        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
        outputStream.flush();
    } catch(Exception e) {
        e.printStackTrace();
        // 异常时返回错误状态和信息
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        response.getWriter().write("文件下载失败:" + e.getMessage());
    }
}

这里用了try-with-resources语法,会自动关闭InputStream,不用手动调用close,避免流泄漏问题。

二、修正前端Ajax代码

原Ajax代码的问题是没有指定响应类型为二进制数据,默认会把响应当成文本处理,导致文件损坏。需要设置responseType: 'blob',然后在成功回调里创建Blob对象,通过临时a标签触发下载:

$('#button').click(function() {
    $.ajax({
        type : "POST",
        data : formToJSON(),
        url: "./test",
        contentType: "application/json",
        xhrFields: {
            responseType: 'blob' // 关键:指定响应为二进制blob类型
        },
        success: function(blob) {
            // 创建临时a标签触发下载
            const downloadLink = document.createElement('a');
            const fileUrl = window.URL.createObjectURL(blob);
            downloadLink.href = fileUrl;
            downloadLink.download = 'download.zip'; // 设置下载的文件名
            document.body.appendChild(downloadLink);
            downloadLink.click();
            // 清理临时资源,避免内存泄漏
            window.URL.revokeObjectURL(fileUrl);
            document.body.removeChild(downloadLink);
        },
        error : function(xhr, status, error) {
            let errMsg = xhr.responseText;
            // 如果错误响应是blob类型,需要转换为文本显示
            if (xhr.response instanceof Blob) {
                const reader = new FileReader();
                reader.onload = function() {
                    document.getElementById("error").innerHTML = reader.result;
                };
                reader.readAsText(xhr.response);
            } else {
                document.getElementById("error").innerHTML = errMsg;
            }
        }
    });
    return false;
});

三、关键知识点说明

  • 后端响应头设置:Content-Type: application/zip告诉浏览器这是压缩文件,Content-Disposition: attachment强制浏览器触发下载动作而不是直接打开文件;
  • 前端responseType:必须设置为blob才能正确接收二进制流,否则会把二进制数据当成UTF-8文本解析,导致下载的文件损坏;
  • Blob对象与临时URL:通过window.URL.createObjectURL把Blob转换成可访问的临时URL,用a标签模拟点击触发下载,完成后要记得释放URL资源避免内存泄漏。

内容的提问来源于stack exchange,提问作者User123

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:22:56