目录
问题描述
原因追踪
解决办法
问题描述
Spring Boot 应用 (使用默认的嵌入式 Tomcat) 在上传文件时, 偶尔会出现上传失败的情况, 后台报错日志信息如下:"The temporary upload location is not valid".
原因追踪
这个问题的根本原因是 Tomcat 的文件上传机制引起的!
Tomcat 在处理文件上传时, 会将客户端上传的文件写入临时目录, 这个临时目录默认在 / tmp 路径下, 如:"/tmp/tomcat.6574404581312272268.18333/work/Tomcat/localhost/ROOT".
而操作系统对于 / tmp 目录会不定时进行清理, 如果正好因为操作系统的清理导致对应的临时目录被删除, 客户端再上传文件时就会报错:"The temporary upload location is not valid".
实际上, 追踪一下源码会发现, 如果不明确设置 Tomcat 的文件上传临时目录, 默认读取的是 Servlet 上下文对象的属性 "javax.servlet.context.tempdir" 值, 如下源码:
- org.apache.catalina.connector.Request
- private void parseParts(boolean explicit) {
- //...
- MultipartConfigElement mce = this.getWrapper().getMultipartConfigElement();
- //...
- // 读取 MultipartConfigElement 对象的 location 属性
- String locationStr = mce.getLocation();
- File location;
- if (locationStr != null && locationStr.length() != 0) {
- location = new File(locationStr);
- if (!location.isAbsolute()) {
- location = (new File((File)context.getServletContext().getAttribute("javax.servlet.context.tempdir"), locationStr)).getAbsoluteFile();
- }
- } else {
- // 如果 location 属性值为空, 则读取 Servlet 上下文对象的属性 "javax.servlet.context.tempdir" 值(如:/tmp/tomcat.6574404581312272268.18333/work/Tomcat/localhost/ROOT)
- location = (File)context.getServletContext().getAttribute("javax.servlet.context.tempdir");
- }
- //...
- }
解决办法
既然是因为上传文件的临时路径被删除导致的问题, 就要确保改临时目录不会被删除.
2 种解决方法:
(1)通过 Spring Boot 的配置参数 "spring.servlet.multipart.location" 明确指定上传文件的临时目录, 确保该路径已经存在, 而且该目录不会被操作系统清除.
spring.servlet.multipart.location=/data/tmp
如上所示, 将上传文件的临时目录指定到路径 "/data/tmp" 下.
实际上, 在 Spring Boot 中关于上传文件的所有配置参数如下所示:
- # MULTIPART (MultipartProperties)
- spring.servlet.multipart.enabled=true # Whether to enable support of multipart uploads.
- spring.servlet.multipart.file-size-threshold=0B # Threshold after which files are written to disk.
- spring.servlet.multipart.location= # Intermediate location of uploaded files.
- spring.servlet.multipart.max-file-size=1MB # Max file size.
- spring.servlet.multipart.max-request-size=10MB # Max request size.
- spring.servlet.multipart.resolve-lazily=false # Whether to resolve the multipart request lazily at the time of file or parameter access.
(2)在 Spring 容器中明确注册 MultipartConfigElement 对象, 通过 MultipartConfigFactory 指定一个路径.
在上述源码追踪中就发现, Tomcat 会使用 MultipartConfigElement 对象的 location 属性作为上传文件的临时目录.
- /**
- * 配置上传文件临时目录
- * @return
- */
- @Bean
- public MultipartConfigElement multipartConfigElement() {
- MultipartConfigFactory factory = new MultipartConfigFactory();
- // tmp.dir 参数在启动脚本中设置
- String path = System.getProperty("tmp.dir");
- if(path == null || "".equals(path.trim())) {
- path = System.getProperty("user.dir");
- }
- String location = path + "/tmp";
- File tmpFile = new File(location);
- // 如果临时目录不存在则创建
- if (!tmpFile.exists()) {
- tmpFile.mkdirs();
- }
- // 明确指定上传文件的临时目录
- factory.setLocation(location);
- return factory.createMultipartConfig();
- }
[参考]
https://stackoverflow.com/questions/50523407/the-temporary-upload-location-tmp-tomcat-4296537502689403143-5000-work-tomcat/50523578 The temporary upload location is not valid
https://blog.csdn.net/llibin1024530411/article/details/79474953 SpringBoot 项目的 The temporary upload location ***is not valid 问题
来源: https://www.cnblogs.com/nuccch/p/11546494.html