当前位置 博文首页 > 范栩的博客:springboot文件上传,文件过大引发异常SizeLimitExc

    范栩的博客:springboot文件上传,文件过大引发异常SizeLimitExc

    作者:[db:作者] 时间:2021-08-31 09:46

    今天在打代码的时候遇到了一个“上传文件过大”的报错,本来是一个小问题,随手百度了一下想要解决。
    但是遇到了一种授人以渔的方法。在学习过后,很是激动,在学习过程中,将之前学的不是很透彻的SpringBoot自动装配机制和不是很熟练的Debug调试都学习串联了起来,有一种恍然大悟的感觉,遂将调试过程记录下来,以免因不熟忘记这种学习思路。

    首先是报错信息

    2021-04-21 12:01:02.305 ERROR 2896 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size exceeded; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException: the request was rejected because its size (70393426) exceeds the configured maximum (10485760)] with root cause
    
    org.apache.tomcat.util.http.fileupload.impl.SizeLimitExceededException: the request was rejected because its size (70393426) exceeds the configured maximum (10485760)
    	at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.init(FileItemIteratorImpl.java:146) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
    	at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.getMultiPartStream(FileItemIteratorImpl.java:190) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
    	at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.findNextItem(FileItemIteratorImpl.java:209) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
    	at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.<init>(FileItemIteratorImpl.java:127) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
    	at org.apache.tomcat.util.http.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:256) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
    	at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:280) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
    	at org.apache.catalina.connector.Request.parseParts(Request.java:2922) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
    	at org.apache.catalina.connector.Request.getParts(Request.java:2824) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
    	at org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1098) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
    	at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:95) ~[spring-web-5.3.5.jar:5.3.5]
    	at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:88) ~[spring-web-5.3.5.jar:5.3.5]
    	at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:87) ~[spring-web-5.3.5.jar:5.3.5]
    	at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1198) ~[spring-webmvc-5.3.5.jar:5.3.5]
    	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1032) ~[spring-webmvc-5.3.5.jar:5.3.5]
    	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962) ~[spring-webmvc-5.3.5.jar:5.3.5]
    	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.5.jar:5.3.5]
    	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.5.jar:5.3.5]
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:652) ~[tomcat-embed-core-9.0.44.jar:4.0.FR]
    	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.5.jar:5.3.5]
    	at javax.servlet.http.HttpServlet.service(HttpServlet.java:733) ~[tomcat-embed-core-9.0.44.jar:4.0.FR]
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
    	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.44.jar:9.0.44]
    	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
    	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.44.jar:9.0.44]
    	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.5.jar:5.3.5]
    	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.
    	...
    

    点击报错信息中最靠上方的类(FileItemIteratorImpl.java:146),会看到关键字sizeMax,然后在这一行打上一个断点,再Debug运行,可以看到sizeMax是从FileUploadBase中传过来的,
    在这里插入图片描述
    然后我们进入FileUploadBase类寻找sizeMax,可以找到sizeMax的get、set方法。在set方法处添加断点然后Debug,按f8下一步,查看sizeMax的值是从哪里传过来的。
    在这里插入图片描述
    通过debug的控制台的变量数据显示,可以看到这个sizeMax的值是从mce中的maxRequestSize里传过来的,点击mce的getMaxRequestSize方法,进入到MultipartConfigElement类中
    在这里插入图片描述
    发现其中没有set方法,设置值只能通过构造方法,所以我们给三个构造方法都打上断点,下方是源代码,

    /*
    * Licensed to the Apache Software Foundation (ASF) under one or more
    * contributor license agreements.  See the NOTICE file distributed with
    * this work for additional information regarding copyright ownership.
    * The ASF licenses this file to You under the Apache License, Version 2.0
    * (the "License"); you may not use this file except in compliance with
    * the License.  You may obtain a copy of the License at
    *
    *     http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
    package javax.servlet;
    
    import javax.servlet.annotation.MultipartConfig;
    
    /**
     * @since Servlet 3.0
     * TODO SERVLET3 - Add comments
     */
    public class MultipartConfigElement {
    
        private final String location;// = "";
        private final long maxFileSize;// = -1;
        private final long maxRequestSize;// = -1;
        private final int fileSizeThreshold;// = 0;
    
        public MultipartConfigElement(String location) {
            // Keep empty string default if location is null
            if (location != null) {
                this.location = location;
            } else {
                this.location = "";
            }
            this.maxFileSize = -1;
            this.maxRequestSize = -1;
            this.fileSizeThreshold = 0;
        }
    
        public MultipartConfigElement(String location, long maxFileSize,
                long maxRequestSize, int fileSizeThreshold) {
            // Keep empty string default if location is null
            if (location != null) {
                this.location = location;
            } else {
                this.location = "";
            }
            this.maxFileSize = maxFileSize;
            this.maxRequestSize = maxRequestSize;
            // Avoid threshold values of less than zero as they cause trigger NPEs
            // in the Commons FileUpload port for fields that have no data.
            if (fileSizeThreshold > 0) {
                this.fileSizeThreshold = fileSizeThreshold;
            } else {
                this.fileSizeThreshold = 0;
            }
        }
    
        public MultipartConfigElement(MultipartConfig annotation) {
            location = annotation.location();
            maxFileSize = annotation.maxFileSize();
            maxRequestSize = annotation.maxRequestSize();
            fileSizeThreshold = annotation.fileSizeThreshold();
        }
    
        public String getLocation() {
            return location;
        }
    
        public long getMaxFileSize() {
            return maxFileSize;
        }
    
        public long getMaxRequestSize() {
            return maxRequestSize;
        }
    
        public int getFileSizeThreshold() {
            return fileSizeThreshold;
        }
    }
    

    启动Debug之后,通过不断的f8我们可以看到,确实是通过构造方法传入了值,然后我们继续下一步。
    在这里插入图片描述
    在这里插入图片描述
    来到了调用MultipartConfigElement构造方法的类——MultipartConfigFactory,这中Factory的类就很熟悉了,大概率是自动生成的。
    在这里插入图片描述
    再下一步,到了MultipartProperties类,这是SpringBoot自动装配的Properties类,
    在这里插入图片描述
    下一步,我们来到了MultipartAutoConfiguration,这就是正宗的自动装配的类了。
    在这里插入图片描述
    看上方的注解,@ConditionalOnMissingBean,如果Spring中没有MultipartConfigElement的Bean,则自动执行。所以我只需要自己写一个返回MultipartConfigElement的方法,在其中更改sizeMax,然后再注入bean,就可以了。

    	@Bean
    	public MultipartConfigElement multipartConfigElement() {
    		MultipartConfigFactory factory = new MultipartConfigFactory();
    		factory.setMaxFileSize(DataSize.ofBytes(1048576*200));//1048567是1Mb
    		factory.setMaxRequestSize(DataSize.ofBytes(1048576*200));
    		return factory.createMultipartConfig();
    	}
    

    在这里插入图片描述

    或者直接在applicationProperties.xml中进行修改

    spring.servlet.multipart.max-request-size=209715201
    spring.servlet.multipart.max-file-size=209715202
    

    在这里插入图片描述
    亲测可行,注意setMaxFileSize只支持DataSize格式的数据

    public void setMaxFileSize(DataSize maxFileSize)
    

    可以通过DataSize的静态方法获得DataSize的对象

    public static DataSize ofBytes(long bytes) {
        return new DataSize(bytes);
    }
    

    最后,感谢我参考的博主,此处挂上原文链接:springboot文件上传,文件过大导致异常the request was rejected because its size (170982031) exceeds the configured

    cs
    下一篇:没有了