如何使用嵌入式 tomcat 在 Spring Boot 中增加文件大小上传限制

Posted

技术标签:

【中文标题】如何使用嵌入式 tomcat 在 Spring Boot 中增加文件大小上传限制【英文标题】:How to increase file size upload limit in spring boot using embedded tomcat 【发布时间】:2020-06-19 05:47:07 【问题描述】:

我正在尝试使用我的 Spring Boot API 上传文件。当我使用小文件(小于 1 MB)时,该功能工作正常,但是当我上传大文件时,它给了我一个异常。我正在使用嵌入式 Tomcat 服务器。

“超出最大上传大小;嵌套异常是 java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException: 字段文件超出了其最大允许大小 1048576 字节。”

我在我的文件中尝试了以下代码,但每次我都收到错误

1.应用程序.property

server.tomcat.max-swallow-size=100MB

server.tomcat.max-http-post-size=100MB

spring.servlet.multipart.enabled=true

spring.servlet.multipart.fileSizeThreshold=100MB

spring.servlet.multipart.max-file-size=100MB

spring.servlet.multipart.max-request-size=100MB

我也试过了

spring.servlet.multipart.maxFileSize=100MB

spring.servlet.multipart.maxRequestSize=100MB

2。爱人是我的文件上传代码

public RestDTO uploadFile(MultipartFile file, String subPath) 

    if (file.isEmpty()) 
        return new RestFailure("Failed to store empty file");
    

    try 
        String fileName = new Date().getTime() + "_" + file.getOriginalFilename();
        String filePath = uploadPath + subPath + fileName;
        if (Objects.equals(file.getOriginalFilename(), "blob")) 
            filePath += ".png";
            fileName += ".png";
        
        File uploadDir = new File(uploadPath + subPath);
        if (!uploadDir.exists()) 
            uploadDir.mkdirs();
        
        FileOutputStream output = new FileOutputStream(filePath);
        output.write(file.getBytes());
        LOGGER.info("File path : " + filePath);

        MediaInfoDTO mediaInfoDTO = getThumbnailFromVideo(subPath, fileName);

        String convertedFileName = convertVideoToMP4(subPath, fileName);

        System.out.println("---------------->" + convertedFileName);

        return new RestData<>(new MediaDetailDTO(mediaInfoDTO.getMediaPath(), convertedFileName,
                mediaInfoDTO.getMediaType(), mediaInfoDTO.getMediaCodec(), mediaInfoDTO.getWidth(),
                mediaInfoDTO.getHeight(), mediaInfoDTO.getDuration()));
     catch (IOException e) 
        LOGGER.info("Can't upload file: " + e.getMessage());
        return new RestFailure("Failed to store empty file");
    

但每次我都遇到同样的异常。

【问题讨论】:

你使用的是哪个版本的 Spring Boot 我使用的是spring boot 2.1.7 spring.servlet.multipart.max-file-sizespring.servlet.multipart.max-request-size 仅适用于 Spring Boot 2.1.7。尝试将它们都设置为 -1(基本上无限制) 我使用了 spring.servlet.multipart.max-file-size=-1 和 spring.servlet.multipart.max-request-size=-1。还是不行 用正确的字节大小更新答案 【参考方案1】:

除了评论,我还可以建议为 Factory MultipartConfigurationElement 创建一个 @Bean 如果您有来自 TomCat 方面的任何限制,这基本上应该覆盖其他限制。

@Bean
public MultipartConfigElement multipartConfigElement() 
    MultipartConfigFactory factory = new MultipartConfigFactory();
    factory.setMaxFileSize(DataSize.ofBytes(100000000L));
    factory.setMaxRequestSize(DataSize.ofBytes(100000000L));
    return factory.createMultipartConfig();

这里DataSize的类型是org.springframework.util.unit.DataSize

参考https://github.com/spring-projects/spring-boot/issues/11284

我怀疑另一个问题可能来自 TomCat maxSwallowSize 如果上述方法不起作用,请参阅 Baeldung 的第 5 点。 https://www.baeldung.com/spring-maxuploadsizeexceeded

【讨论】:

没有必要这样做。 Spring Boot 将使用spring.servlet.multipart.* 属性自动配置MultipartConfigElement【参考方案2】:

在查看了许多示例并进行了多次测试但没有结果之后。我已经设法通过以下配置解决了这个问题:

    在 pom 中添加以下依赖项:

    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.4</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.6</version>
    </dependency>
    

    从 yml 中删除:

    sprint:
      servlet:  
        multipart:
          enabled: true
          file-size-threshold: 2KB
          max-file-size: 10MB
          max-request-size: 10MB
    

    添加到 yml:

    server:
      tomcat:
        max-swallow-size: -1
        max-http-form-post-size: -1
    

    最后但同样重要的是:

    @Bean
    public MultipartResolver multipartResolver() 
        CommonsMultipartResolver resolver
           = new CommonsMultipartResolver();
        resolver.setDefaultEncoding(StandardCharsets.UTF_8.displayName());
        resolver.setMaxUploadSize(52428800L); //50MB
        resolver.setMaxUploadSizePerFile(52428800L); //50MB
    
        return resolver;
    
    
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public ResponseEntity<Object> handleFileUploadError(MaxUploadSizeExceededException ex) 
        return ResponseEntity.status(EXPECTATION_FAILED).body(
            CustomResponse.builder()
                .status(Status.ERROR)
                .message(ex.getMessage())
                .build());
    
    
    // Where CustomResponse class is in my case:
    /**
      * The UploadResponse class
      * <p>
      * Contain the response body
      */
    @Getter
    @Builder(toBuilder = true)
    @AllArgsConstructor
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public class CustomResponse 
        /**
          * The status
          */
        private final Status status;
        /**
          * The message
          */
        private final String message;
        /**
          * The errors
          */
        private final Set<String> errors;
    
    

【讨论】:

自定义异常处理程序很好,否则你会得到一个丑陋的500 Internal Server 错误,这是由 Sprint 的默认异常处理程序提供的。但是,要增加文件大小限制,我所要做的就是将spring.servlet.multipart.max-file-size=10485760 添加到我的application.properties。无需创建自定义 MultipartResolver bean。

以上是关于如何使用嵌入式 tomcat 在 Spring Boot 中增加文件大小上传限制的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Spring Boot 嵌入式 tomcat 设置会话超时

如何使用嵌入式 Tomcat 容器在 Spring Boot 中创建 JNDI 上下文

如何使用 Spring Boot 和嵌入式 Tomcat 配置此属性?

如何在 Spring Boot 中关闭嵌入式 Tomcat?

使用嵌入式 Tomcat 启动 Spring Boot 应用程序时如何配置堆大小?

如何在带有嵌入式 tomcat 的 Spring Boot App 中设置域名