Spring Boot upload on Linux found no temporary directory and encountered 500 errors

Error Reason

On Linux systems, when Spring Boot applications are started with java-jar commands, a tomcat (or undertow) temporary directory is generated in the operating system's / tmp directory, where the uploaded files are first converted to temporary files and saved.Because of the files in the temporary/tmp directory, the system executed the TMP directory cleaning service (systemd-tmpfiles-clean.service) without using it for a long time (10 days).Causes / tmp/undertow...8090 files to be cleaned up, however, during upload, the undertow server needs to create / tmp/undertow...8090/undertow...upload temporary files, but when calling Files.createFile(...), it will find that the parent directory cannot be found, which causes the above error.

Specific error log (reference)

undertow

java.nio.file.NoSuchFileException: /tmp/undertow.17753558642503713859.8085/undertow7370242804103803588upload

Tomcat

The temporary upload location [/tmp/tomcat.7957874575370093230.8088/work/Tomcat/localhost/ROOT] is not valid

Reproduction Method

Find the class io.undertow.server.handlers.form.MultiPartParserDefinition
Locate the following code

@Override
public void beginPart(final HeaderMap headers) {
    this.currentFileSize = 0;
    this.headers = headers;
    final String disposition = headers.getFirst(Headers.CONTENT_DISPOSITION);
    if (disposition != null) {
        if (disposition.startsWith("form-data")) {
            currentName = Headers.extractQuotedValueFromHeader(disposition, "name");
            fileName = Headers.extractQuotedValueFromHeaderWithEncoding(disposition, "filename");
            if (fileName != null && fileSizeThreshold == 0) {
                try {
                    if (tempFileLocation != null) {
                        file = Files.createTempFile(tempFileLocation, "undertow", "upload");
                    } else {
                        file = Files.createTempFile("undertow", "upload");
                    }
                    createdFiles.add(file);
                    fileChannel = FileChannel.open(file, StandardOpenOption.READ, StandardOpenOption.WRITE);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

At createdFiles.add(file); breakpoint, copy the value of file's path to find the file and delete it; breakpoint, error recurrence;

Solution

Option 1 (Recommended)

Add configuration to applicaiton.yml(applicaiton.property): spring.servlet.multipart.location The bottom level of spring.servlet.multipart.location is factory.setLocation in createMultipartConfig, see source: org.springframework.boot.autoconfigure.web.servlet.MultipartProperties#createMultipartConfig

spring:
  servlet:
    multipart:
      location: /data/tmp

After specifying a directory manually, you must ensure that it exists and that it has read and write permissions
Create the directory mkdir-p/data/tmp

Method 2

Use configuration class configuration, similar to scenario 1

@Bean
public MultipartConfigElement multipartConfigElement() {
    MultipartConfigFactory factory = new MultipartConfigFactory();
    factory.setLocation(System.getProperty("/data/tmp"));
    return factory.createMultipartConfig();
}

Option 3 (not recommended)

Manually create temporary directory

mkdir -p /tmp/undertow.17753558642503713859.8085/undertow7370242804103803588upload

Option 4 (not recommended)

Modify the system configuration to exclude the temporary directory

vim /usr/lib/tmpfiles.d/tmp.con
# File last added
x /tmp/undertow*

Original Link: Spring Boot upload under Linux failed to find temporary directory, 500 errors occurred

Tags: Programming Spring Tomcat Linux Java

Posted on Sun, 26 Apr 2020 10:07:48 -0700 by farel