Spring REST Controller上传文件出现额外数据导致文件损坏问题咨询
问题根因分析
1. 核心错误:InputStream.available()方法的误用
注意:
available()方法的返回值仅代表当前时刻无需阻塞就能读取的字节数,绝对不能用来作为整个流的总长度。在原生Servlet环境下刚好一次能读到全部内容属于巧合,换到Spring环境下因为请求流的包装逻辑不同,才暴露了这个问题。
你写的读取代码本身就存在逻辑缺陷,read()方法也不保证能一次性读完你指定长度的字节,当前写法大概率会读到不完整的数据,或者因为缓冲区没填充满留下大量空字节,这就是你文件变大、损坏的直接原因。
2. Spring环境的额外影响
Spring MVC默认会自动注册MultipartResolver来解析multipart/form-data类型的请求,你在Controller里还自己用ServletFileUpload去读请求流的话,相当于对同一个multipart请求做了两次解析,流已经被Spring的解析逻辑读过/包装过,自然读出来的内容和原生Servlet环境下不一致。
修复方案
- 方案1(推荐):使用Spring标准的文件上传接口
直接用MultipartFile接收上传文件,不需要自己处理FileItem:
如果你一定要保留自己的解析逻辑,需要关闭Spring默认的multipart自动解析,在Spring Boot配置文件中添加:@PostMapping("/upload") public String upload(@RequestParam("你定义的文件参数名") MultipartFile file) throws IOException { // 直接获取完整的文件字节 byte[] bytes = file.getBytes(); // 后续业务逻辑 }spring.servlet.multipart.enabled = false - 方案2:修复原有的流读取逻辑
如果必须用FileItem的方式读取,要正确读取整个流的内容,不要用available()判断长度:FileItem item = ...; try (InputStream inputStream = item.getInputStream()) { // JDK9及以上可以直接调用readAllBytes方法 byte[] bytes = inputStream.readAllBytes(); // 如果是JDK8及以下版本,用ByteArrayOutputStream中转读取 /* ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; int len; while ((len = inputStream.read(buffer)) != -1) { baos.write(buffer, 0, len); } byte[] bytes = baos.toByteArray(); */ }
内容的提问来源于stack exchange,提问作者algiogia
相关产品推荐
相关产品推荐

