Brian K.
Brian K.

Reputation: 71

Spring Boot + Multipart file upload yields a Badly formatted multipart request

I am currently running with Spring Boot v1.3.0.BUILD-SNAPSHOT, and Spring v4.2.2.BUILD-SNAPSHOT.

If I attempt to perform a multi-file upload (via angular):

myService.upload = function(name ,content) {
    var fd = new FormData();
    fd.append('name', name);
    fd.append('file', content);   

    return $http({
      method: 'POST',
      url: SERVER_BASE_URL + 'upload',
      data: fd,
      transformRequest: angular.identity,
      headers: {
        'Content-Type': 'multipart/form-data'
      }}).then(function(res) {       
        return res.headers('Location');
      }, function(reason) {
          throw reason;
      });
};

I get the error:

[WARN] org.eclipse.jetty.server.Request - java.io.IOException: Missing initial multi part boundary at org.eclipse.jetty.util.MultiPartInputStreamParser.parse(MultiPartInputStreamParser.java:507) ~[jetty-util-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.util.MultiPartInputStreamParser.getParts(MultiPartInputStreamParser.java:400) ~[jetty-util-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.Request.getParts(Request.java:2139) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.Request.extractMultipartParameters(Request.java:385) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.Request.extractContentParameters(Request.java:308) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.Request.extractParameters(Request.java:256) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.Request.getParameter(Request.java:825) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:70) [spring-web-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT] at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) [jetty-servlet-9.2.13.v20150730.jar:9.2.13.v20150730] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85) [spring-web-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT] at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.2.2.BUILD-SNAPSHOT.jar:4.2.2.BUILD-SNAPSHOT] at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1652) [jetty-servlet-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.ja [jetty-servlet-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:577) [jetty-security-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:223) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1127) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515) [jetty-servlet-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1061) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.Server.handle(Server.java:499) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:310) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257) [jetty-server-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540) [jetty-io-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635) [jetty-util-9.2.13.v20150730.jar:9.2.13.v20150730] at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555) [jetty-util-9.2.13.v20150730.jar:9.2.13.30]1507 at java.lang.Thread.run(Thread.java:745) [na:1.8.0_45]

I have added A multipart resolver bean:

@Bean
public FilterRegistrationBean openEntityManagerFilterRegistrationBean() {
    // Set upload filter
    final MultipartFilter multipartFilter = new MultipartFilter();
    final FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(multipartFilter);
    filterRegistrationBean.addInitParameter("multipartResolverBeanName", "commonsMultipartResolver");

    return filterRegistrationBean;
}

@Bean
public CommonsMultipartResolver commonsMultipartResolver() {
    final CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
    commonsMultipartResolver.setMaxUploadSize(-1);

    return commonsMultipartResolver;
}

However it appears that hiddenHttpMethodFilter is still getting called before my multipart resolver:

[DEBUG] org.eclipse.jetty.servlet.ServletHandler - call filter characterEncodingFilter [DEBUG] org.eclipse.jetty.servlet.ServletHandler - call filter hiddenHttpMethodFilter [WARN] org.eclipse.jetty.util.MultiPartInputStreamParser - Badly formatted multipart request

I tried adding @Order(0) to my Bean, but that had no effect.

What else am I missing?

Upvotes: 7

Views: 6396

Answers (2)

Abhishek Anand
Abhishek Anand

Reputation: 1992

Well this simply means there is issue with your angular js code. You will have to debug on browser, what exactly is being sent, and definately it is missing headers. Use tools like firebug. Try this code.

var fd = new FormData();
fd.append('file', file);
fd.append('data', 'string');
$http.post(uploadUrl, fd, {
   transformRequest: angular.identity,
   headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});

Absolutely essential are the following two properties of the config object:

transformRequest: angular.identity

overrides Angular's default serialization, leaving our data intact.

headers: {'Content-Type': undefined }

lets the browser detect the correct Content-Type as multipart/form-data, and fill in the correct boundary.

Upvotes: 0

Douglas Ribeiro
Douglas Ribeiro

Reputation: 3005

I do not use filter to upload files.

Try this approach here:

// in configs
  @Bean
     Public MultipartConfigElement multipartConfigElement () {
         End MultipartConfigFactory factory = new MultipartConfigFactory ();
         Factory.setMaxFileSize ( "50MB");
         Factory.setMaxRequestSize ( "50MB");
         Return factory.createMultipartConfig ();
     }

and

        // in controller
         @RequestMapping (value = "/ sendfile", method = RequestMethod.POST)
         Public ModelAndView formSubmit (@RequestParam ( "file") MultipartFile file) {

         }

Note: remember to remove the filters that you put in the configs

I hope to help

Upvotes: 2

Related Questions