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

POST请求下载Excel文件时不传null导致文件损坏问题排查

POST请求下载Excel不传请求体导致文件损坏的原因

我在通过POST请求下载Excel文件时发现:当客户端代码中指定请求体为null时,文件可正常下载并打开;但不指定null时,文件虽能下载,打开却显示损坏。使用GET请求则可正常下载。

后端代码

@RequestMapping(value = "/download", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
public void downloadTemplateFiles(HttpServletResponse response) {
    try {
        ServletOutputStream myOut;
        BufferedInputStream buf;
        myOut = response.getOutputStream();
        ClassPathResource inputFile = new ClassPathResource("excel/Temp.xlsx");
        InputStream input = inputFile.getInputStream();
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment; filename=\"" + inputFile.getFilename() + "\"");
        buf = new BufferedInputStream(input);
        int readBytes;
        while ((readBytes = buf.read()) != -1) {
            myOut.write(readBytes);
        }
        myOut.flush();
        myOut.close();
    } catch (Exception e) {
        log.error(ExceptionUtils.getStackTrace(e));
    }
}

前端代码

const generate = async () => {
    try {
        const response = await axios.post('download',null, {
            responseType: 'arraybuffer'
        });
        if (response.status === 200) {
            downloadFile(response.data, 'Temp.xlsx', "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            message.success("Report Template Dowloaded Successfully")
        } else {
            message.error("Error dowloading report.");
        }
    } catch (error) {
        console.error("Error downloading report:", error);
        message.error("Error downloading report.");
    }
};
const downloadFile = (content, filename, Type) => {
    const blob = new Blob([content], { type: Type });
    const url = window.URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    window.URL.revokeObjectURL(url);
    document.body.removeChild(a);
};

原因分析

1. Axios的默认请求行为差异

当调用axios.post('download', null, ...)时,请求体被明确设为null,Axios会发送内容为"null"的JSON请求体,且携带application/json的Content-Type头。但省略第二个参数(不传null)时,Axios会默认发送空JSON对象{}作为请求体,同样携带application/json头。

2. Spring MVC的请求体解析冲突

后端接口的@RequestMapping声明了produces = MediaType.APPLICATION_JSON_VALUE,但实际返回的是Excel二进制流。当Spring MVC接收到application/json类型的请求体时,会尝试用JSON消息转换器解析,但接口方法没有声明@RequestBody参数接收请求体,这会触发Spring内部的解析逻辑异常。

尽管方法捕获了自身代码的异常,但Spring的异常处理机制可能已向响应输出流写入了部分JSON格式的错误信息。之后方法继续写入Excel二进制数据,导致响应内容是错误信息+Excel二进制数据的混合体,直接破坏了Excel文件结构。

而传null作为请求体时,Spring解析到请求体是合法的JSON值(null),即使没有对应接收参数,也不会触发异常,响应流中只有Excel二进制数据,文件可正常打开。

3. 额外优化点

  • 后端接口produces设置错误,应改为Excel对应的MIME类型MediaType.APPLICATION_OCTET_STREAM_VALUE或"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",避免Spring做不必要的JSON格式处理。
  • 后端读取文件流的方式效率极低,建议用字节数组批量读取:
    byte[] buffer = new byte[1024];
    int len;
    while ((len = buf.read(buffer)) != -1) {
        myOut.write(buffer, 0, len);
    }
    
  • 如果接口不需要请求体,更推荐使用GET请求(已验证可正常工作),避免POST请求体带来的额外问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:07:13