我的配置是here

我根据该帖子中的答案进行了一些修改。

filterMultipartResolver

@Bean
public StandardServletMultipartResolver filterMultipartResolver() {
    return new StandardServletMultipartResolver();
}

AppInitializer
public class AppInitializer implements WebApplicationInitializer {

    @Override
    public void onStartup(final ServletContext servletContext) throws ServletException {
        // Create the 'root' Spring application context
        final WebApplicationContext context = getContext();
        // Manage the lifecycle of the root application context
        servletContext.addListener(new ContextLoaderListener(context));
        final Dynamic dispatcher = servletContext.addServlet("DispatcherServlet", new DispatcherServlet(context));
        dispatcher.setMultipartConfig(getMultipartConfigElement());
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }

    private static AnnotationConfigWebApplicationContext getContext() {
        final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.register(AppConfig.class);
        return context;
    }

    private static MultipartConfigElement getMultipartConfigElement(){
        return new MultipartConfigElement(Props.FILE_TMP_DIRECTORY, 3 * 1024 * 1024, 3 * 1024 * 1024, 3 * 1024 * 1024);
    }
}

我遵循了this post的建议,并包含了这个MultipartExceptionHandler
public class MultipartExceptionHandler extends OncePerRequestFilter {
    static final Logger log = LoggerFactory.getLogger(MultipartExceptionHandler.class);

    @Override
    protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException {
        try {
            filterChain.doFilter(request, response);
        } catch (final MultipartException me) {
            log.error(me.getMessage());
            response.sendRedirect(UrlUtils.buildFullRequestUrl(request) + "&error=size-limit");
        }
    }
}

注册在
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

    @Override
    protected void beforeSpringSecurityFilterChain(final ServletContext servletContext) {
        insertFilters(servletContext, new MultipartExceptionHandler());
        insertFilters(servletContext, new MultipartFilter());
    }
}

当我尝试上传超过最大大小的文件时,这就是我在日志中看到的
DEBUG 2015-03-17 19:54:18,372: org.springframework.web.multipart.support.MultipartFilter - Using MultipartResolver 'filterMultipartResolver' for MultipartFilter
DEBUG 2015-03-17 19:54:18,372: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'filterMultipartResolver'
DEBUG 2015-03-17 19:54:18,372: org.springframework.web.multipart.support.MultipartFilter - Resolving multipart request [/registrazione] with MultipartFilter
ERROR 2015-03-17 19:54:18,384: it.openex.pmfew.filters.MultipartExceptionHandler - Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (4522604) exceeds the configured maximum (3145728)
DEBUG 2015-03-17 19:54:18,386: org.springframework.web.multipart.support.MultipartFilter - Using MultipartResolver 'filterMultipartResolver' for MultipartFilter
DEBUG 2015-03-17 19:54:18,386: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'filterMultipartResolver'
DEBUG 2015-03-17 19:54:18,386: org.springframework.web.multipart.support.MultipartFilter - Resolving multipart request [/registrazione] with MultipartFilter
ERROR 2015-03-17 19:54:18,386: it.openex.pmfew.filters.MultipartExceptionHandler - Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (4522604) exceeds the configured maximum (3145728)

它会重复7次,并且不会在过滤器中指定重定向:我只是得到一个空白页。

我不确定会发生什么,因为有时在过滤器中添加调试断点可以使其工作,甚至添加Thread.sleep(100)
更新1

有关此问题的更多信息。

每次我重新启动Tomcat时,过滤器可能被调用2次或7次。
只有一个POST调用。

chrome中的响应为(failed) net::ERR_CONNECTION_RESET

该请求是org.apache.catalina.connector.RequestFacade的实例,其中包含org.apache.catalina.connector.Request的实例。在后者内部,属性partsParseException携带日志中显示的异常。
每次请求都是相同的。

链中有4个过滤器:
  • MultipartExceptionHandler(我添加的过滤器)
  • org.springframework.web.multipart.support.MultipartFilter
  • org.springframework.web.filter.DelegatingFilterProxy
  • org.apache.tomcat.websocket.server.WsFilter

  • 我将Tomcat升级到了最新版本:8.0.20。

    我试图重定向到一个简单的URL(例如/),并在过滤器中捕获各种异常,包括catch块可能抛出的异常。

    结果是这样的
    public class MultipartExceptionHandler extends OncePerRequestFilter {
        static final Logger log = LoggerFactory.getLogger(MultipartExceptionHandler.class);
        @Override
        protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain) throws ServletException, IOException {
            try {
                filterChain.doFilter(request, response);
            } catch (final MultipartException me) {
                try{
                    log.error(me.getMessage());
                    response.sendRedirect(UrlMap.HOME);
                } catch (final Exception e){
                    log.error(e.getMessage());
                }
    
            }catch (final Exception e){
                log.error(e.getMessage());
            }
        }
    }
    

    令人不安的是,它似乎并没有确定性的表现:使用Intellij Idea,有时我将断点放入“MultipartExceptionHandler”的catch块中,然后恢复程序即可正常工作。

    如果没有,我只需要重新启动Tomcat 1到2次,直到技巧再次起作用即可。

    没有断点,该程序将永远无法运行。

    更新2

    我对应用程序的行为进行了更多测试。

    我发现它只是不时地开箱即用,而无需重新启动Tomcat或进行任何花哨的操作。

    可以尝试重新上传文件,直到文件顺利为止,如果出现错误,请按浏览器的“后退”按钮以返回到上传页面。

    它工作4-5次中的1次,没有任何明显的重复模式。

    如果失败,这就是堆栈跟踪。在日志中,它连续重复2次,之后没有其他任何内容了。
    INFO  2015-03-18 12:21:59,870: it.openex.pmfew.filters.MultipartExceptionHandler - #############################
    INFO  2015-03-18 12:21:59,870: it.openex.pmfew.filters.MultipartExceptionHandler - /registrazione?execution=e3s2
    INFO  2015-03-18 12:21:59,870: it.openex.pmfew.filters.MultipartExceptionHandler - #############################
    DEBUG 2015-03-18 12:21:59,870: org.springframework.web.multipart.support.MultipartFilter - Using MultipartResolver 'filterMultipartResolver' for MultipartFilter
    DEBUG 2015-03-18 12:21:59,870: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'filterMultipartResolver'
    DEBUG 2015-03-18 12:21:59,870: org.springframework.web.multipart.support.MultipartFilter - Resolving multipart request [/registrazione] with MultipartFilter
    ERROR 2015-03-18 12:21:59,870: it.openex.pmfew.filters.MultipartExceptionHandler - Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (4522604) exceeds the configured maximum (3145728)
    org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (4522604) exceeds the configured maximum (3145728)
        at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:99)
        at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:77)
        at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:76)
        at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:108)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at it.openex.pmfew.filters.MultipartExceptionHandler.doFilterInternal(MultipartExceptionHandler.java:29)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
        at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1086)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:659)
        at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1558)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1515)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)
    Caused by: java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (4522604) exceeds the configured maximum (3145728)
        at org.apache.catalina.connector.Request.parseParts(Request.java:2792)
        at org.apache.catalina.connector.Request.getParts(Request.java:2636)
        at org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1083)
        at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:84)
        ... 27 more
    Caused by: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (4522604) exceeds the configured maximum (3145728)
        at org.apache.tomcat.util.http.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:811)
        at org.apache.tomcat.util.http.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:256)
        at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:280)
        at org.apache.catalina.connector.Request.parseParts(Request.java:2725)
        ... 30 more
    

    相反,如果进展顺利,则只显示一次stacktrace,然后将其追加(由于帖子的大小限制,我删除了一些部分)
    INFO  2015-03-18 12:20:38,789: it.openex.pmfew.filters.MultipartExceptionHandler - #############################
    INFO  2015-03-18 12:20:38,789: it.openex.pmfew.filters.MultipartExceptionHandler - Url called -> /registrazione?execution=e1s2&error=size-limit
    INFO  2015-03-18 12:20:38,789: it.openex.pmfew.filters.MultipartExceptionHandler - #############################
    DEBUG 2015-03-18 12:20:38,789: org.springframework.web.multipart.support.MultipartFilter - Using MultipartResolver 'filterMultipartResolver' for MultipartFilter
    DEBUG 2015-03-18 12:20:38,789: org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'filterMultipartResolver'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.web.multipart.support.MultipartFilter - Request [/registrazione] is not a multipart request
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit at position 1 of 13 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit at position 2 of 13 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.context.HttpSessionSecurityContextRepository - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@2fabad6. A new one will be created.
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit at position 3 of 13 in additional filter chain; firing Filter: 'HeaderWriterFilter'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit at position 4 of 13 in additional filter chain; firing Filter: 'CharacterEncodingFilter'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit at position 5 of 13 in additional filter chain; firing Filter: 'CsrfFilter'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit at position 6 of 13 in additional filter chain; firing Filter: 'LogoutFilter'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit at position 7 of 13 in additional filter chain; firing Filter: 'UsernamePasswordAuthenticationFilter'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit at position 8 of 13 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit at position 9 of 13 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit at position 10 of 13 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit at position 11 of 13 in additional filter chain; firing Filter: 'SessionManagementFilter'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit at position 12 of 13 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit at position 13 of 13 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.access.intercept.FilterSecurityInterceptor - Secure object: FilterInvocation: URL: /registrazione?execution=e1s2&error=size-limit; Attributes: [permitAll]
    DEBUG 2015-03-18 12:20:38,789: org.springframework.security.web.FilterChainProxy - /registrazione?execution=e1s2&error=size-limit reached end of additional filter chain; proceeding with original chain
    DEBUG 2015-03-18 12:20:38,789: org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'DispatcherServlet' processing GET request for [/registrazione]
    DEBUG 2015-03-18 12:20:38,789: org.springframework.webflow.mvc.servlet.FlowHandlerMapping - Mapping request with URI '/registrazione' to flow with id 'registrazione'
    DEBUG 2015-03-18 12:20:38,789: org.springframework.webflow.executor.FlowExecutorImpl - Resuming flow execution with key 'e1s2
    DEBUG 2015-03-18 12:20:38,790: org.springframework.webflow.conversation.impl.SessionBindingConversationManager - Locking conversation 1
    DEBUG 2015-03-18 12:20:38,790: org.springframework.webflow.execution.repository.impl.DefaultFlowExecutionRepository - Getting flow execution with key 'e1s2'
    DEBUG 2015-03-18 12:20:38,790: org.springframework.webflow.definition.registry.FlowDefinitionRegistryImpl - Getting FlowDefinition with id 'registrazione'
    DEBUG 2015-03-18 12:20:38,809: org.springframework.webflow.execution.repository.impl.DefaultFlowExecutionRepository - Putting flow execution '[FlowExecutionImpl@23da7555 flow = 'registrazione', flowSessions = list[[FlowSessionImpl@4c63c9fd flow = 'registrazione', state = 'companyLogo', scope = map['viewScope' -> map['fileForm' -> it.openex.pmcommonw.form.FileForm@ae6eeae], 'menuDTO' -> list[it.openex.pmfew.dtos.MenuEntryDTO@2fcdd386, it.openex.pmfew.dtos.MenuEntryDTO@3ba665a6, it.openex.pmfew.dtos.MenuEntryDTO@5767063d], 'userCompanyInfoForm' -> it.openex.pmcommonw.form.UserCompanyInfoForm@6ac911e1]]]]' into repository
    DEBUG 2015-03-18 12:20:38,810: org.springframework.webflow.execution.repository.impl.DefaultFlowExecutionRepository - Adding snapshot to group with id 2
    DEBUG 2015-03-18 12:20:38,813: org.springframework.webflow.conversation.impl.SessionBindingConversationManager - Unlocking conversation 1
    DEBUG 2015-03-18 12:20:38,813: org.springframework.web.servlet.DispatcherServlet - Successfully completed request
    DEBUG 2015-03-18 12:20:38,813: org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally
    

    更新3

    到目前为止,我尝试上传4.5MB大的文件。

    相反,使用30MB的文件将永远无法使用。

    更新4

    在“时序”选项卡上的Chrome开发人员工具中查看POST请求,我可以看到该请求已停止。 More info about this state.

    Firefox每次使用4.5MB的大文件时,都可以正确重定向到错误页面。如果文件较大(例如7MB),则无法使用,浏览器会返回该消息
    The connection was reset
    
    The connection to the server was reset while the page was loading.
    

    更新5

    MultipartExceptionHandler内部切换行
    response.sendRedirect(UrlUtils.buildFullRequestUrl(request) + "&error=size-limit");
    


    final RequestDispatcher requestDispatcher = request.getRequestDispatcher("/");
    requestDispatcher.forward(request, response);
    

    在Chrome浏览器中,它的工作效率是4的3倍,并且对于大文件,它总是会像往常一样失败。日志中没有任何变化。

    最佳答案

    听起来像是多个请求。根据日志,在发生异常时会调用MultipartExceptionHandler



    也许您可以在protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain)之后添加一个记录器,在此处设置一个断点并检查请求。该请求可能为null或其他原因,原因是



    在这种情况下,UrlUtils.buildFullRequestUrl(request)也将引发未捕获的异常。

    public final class UrlUtils {
        public static String buildFullRequestUrl(HttpServletRequest r) {
             return buildFullRequestUrl(r.getScheme(), r.getServerName(), r.getServerPort(), r.getRequestURI(),
                     r.getQueryString());
        }
    ...
    

    尝试像response.sendRedirect(uri + "&error=size-limit")一样手动设置重定向uri。这意味着响应不能为空。

    尝试为具有模拟请求和模拟异常的文件上传编写测试,并声明预期的重定向uri。

    关于java - 如何在Spring中处理MultipartException,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29107666/

    10-12 02:57
    查看更多