前因
在处理非文件上传的请求时,Spring抛出了一个关于Multipart请求解析的错误。
错误日志
Failed to parse multipart servlet request; nested exception is java.io.IOException: The temporary upload location [/tmp/tomcat.8656187483509135391.8020/work/Tomcat/localhost/ROOT] is not valid
org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is java.io.IOException: The temporary upload location [/tmp/tomcat.8656187483509135391.8020/work/Tomcat/localhost/ROOT] is not valid
这个错误在描述上来看是发生在文件上传接口,但是报错的接口是非上传文件接口,之前没有遇到过所以记录一下
出现原因
- 请求头设置不正确,经过排查前端请求接口请求头
Content-Type
设置成了multipart/form-data
,所以会出现非上传接口出现MultipartException
- Servlet临时目录不存在,
Servlet
接收上传文件时会在/tmp
目录下创建临时目录提高性能,所以在服务启动的时候会创建tmp/tomcat.8656187483509135391.8020/work/Tomcat/localhost/ROOT
临时目录,但是由于CentOS
会清除临时文件,所以才会出现这个报错
解决方法
1. 修改配置
- 设置正确的请求头
- 检查
/tmp/tomcat.8656187483509135391.8020/work/Tomcat/localhost/ROOT
是否正常,避免再出现这样的问题,手动配置指定路径spring:servlet:multipart:location: /path/to
2. 设置CentOS
清除临时目录忽略
在下面这个文件中增加一行配置
/usr/lib/tmpfiles.d/tmp.conf
增加内容
X /tmp/tomcat.*
以上两个方案选其一即可
另外收获
在查看Spring Boot
源码的时候看到下面这段代码👇
/** * Create a new {@link MultipartConfigElement} using the properties. * @return a new {@link MultipartConfigElement} configured using there properties * */public MultipartConfigElement createMultipartConfig() { MultipartConfigFactory factory = new MultipartConfigFactory(); PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); map.from(this.fileSizeThreshold).to(factory::setFileSizeThreshold); map.from(this.location).whenHasText().to(factory::setLocation); map.from(this.maxRequestSize).to(factory::setMaxRequestSize); map.from(this.maxFileSize).to(factory::setMaxFileSize); return factory.createMultipartConfig();}
在生成写入MultipartConfigFactory
属性时,PropertyMapper
减少了很多if
,可读性更强也更加优雅,在日常开发中实用性很强