SpringBoot 多文件上传、携带参数
参考文章:
- https://stackoverflow.com/questions/36005436/the-request-was-rejected-because-no-multipart-boundary-was-found-in-springboot
- http://6tt.co/sUur
问题:
- 多文件上传 携带参数获取为 null
- Failed to parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
解决方案:
先直接上代码,等会再说问题的原因。
前端:
表单上传
<form id="upmore">
<input type="file" name="fileList" value="请选择文件" multiple id="file1">
<input type="file" name="fileList" value="请选择文件" multiple id="file2">
<input type="text" name="content" value="hahahahahahaha" multiple id="content">
<input type="button" onclick="doUpload2()" value="上传2">
</form>
<script src="../js/jquery-3.4.1.min.js"></script>
<script>
function doUpload2() {
let form = new FormData($("#upmore")[0])
console.log(form.get("content"))
var settings = {
"url": "http://localhost/tps/scp/feedback/commit",
"method": "POST",
"timeout": 0,
"headers": {
"token": "5f1b9ff0e4b08b8a8fa3d106374864651320e976dfef314722b1a9529dfcdc828e"
},
"processData": false,
"mimeType": "multipart/form-data",
"contentType": false,
"data": form
};
$.ajax(settings).done(function (response) {
console.log(response);
});
}
</script>
后端:
@Configuration
public class BeanConfig {
@Bean(name = "multipartResolver")
public MultipartResolver multipartResolver(){
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setDefaultEncoding("UTF-8");
resolver.setResolveLazily(true);//resolveLazily属性启用是为了推迟文件解析,以在在UploadAction中捕获文件大小异常
resolver.setMaxInMemorySize(40960);
resolver.setMaxUploadSize(50*1024*1024);//上传文件大小 50M 50*1024*1024
return resolver;
}
}
@PostMapping("/scp/feedback/commit")
public R commit(@RequestParam(required = false) List<MultipartFile> fileList, String content,
HttpServletRequest request) throws FileUploadException {
System.out.println(fileList.size() + " " + content);
// ......
return null;
}
分析
接口写好之后,我通常会直接使用postman先行测试,随后再拿到前端使用。如图最基本的测试,是通过了的。
接着,我将postman生成的ajax代码拷贝了一份,直接拿到了前端使用。出乎意料之外的事情发生,居然报错了:
The request was rejected because no multipart boundary was found in springboot
翻译成中文就是该请求被拒绝,因为在springboot中找不到多部分边界
随之我有测试了几次,postman中请求可以成功,但是在浏览器中接口就会报错。
通过postman生成标准接口的请求代码,这非常方便。(小技巧)
在stackoverflow的一篇文章中,我找到了解决方案,使用postman生成上传文件的ajax代码时,不需要手动填写content-type请求头,postman会自动我们决定。随后,生成的正确代码也确实测试通过了。
接着在使用FormData的方式上传文件时,会出现携带的参数在后端获取为null值的情况。最终在一位网友的博客中找到了解决方案。博客中也将原因阐述的很清楚:
产生的原因就是对于multipart/formdata的请求,SpringMVC没有提供默认解析器,导致请求无法正确的被解析。需要我们自己提供一个org.springframework.web.multipart.MultipartResolver解析器。
虽然说的是SpringMVC,但是对于SpringBoot来说同样适用。在上面的代码中,通过在Java config 中配置bean的方式注入了MultipartResolver解析器。
到此,两个问题全部被解决。
事实上,在之前的代码编写过程中,处理文件上传相关的业务,我的做法都是将文件与参数进行分开处理的,对于小文件来说,这可能是不错的做法,可以提高接口的效率。但是对于大文件来说,接口效率本就不高,将请求参数与文件一并传递,倘若接口请求失败,可以即时删除占用磁盘空间的文件,减少数据冗余。