Search code examples
file-uploadmultipartform-dataangular8spring5

Current request is not a multipart when posting a file to a spring controller


I am trying to send a multipart request to the server but i am getting the following exception

org.springframework.web.multipart.MultipartException: Current request is not a multipart request
    at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:188)
    at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:104)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)

Basing on tutorials and stackoverflow questions i have developped the folowing code

Controller

  @RequestMapping(value = "/upload-file", method = RequestMethod.POST)
    public ResponseEntity<Void> getUploadFile(@RequestParam("file") MultipartFile file) {
    LOGGER.debug(String.valueOf(file));}

MultipartConfiguration

@Configuration
@EnableWebMvc
public class MultipartConfiguration {

    private static final String DEFAULT_ENCODING = "UTF-8";

    private static final long MAX_UPLOAD_FILE_SIZE = 100000000;

    @Bean
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver resolver=new CommonsMultipartResolver();
        resolver.setDefaultEncoding("utf-8");
        resolver.setMaxUploadSize(MAX_UPLOAD_FILE_SIZE);
        resolver.setDefaultEncoding(DEFAULT_ENCODING);
        return resolver;
    }
}

html

<input type="file"  style="display:none" #fileupload name="image" (change)="fileProgress($event)" />

Component

export class FileUploadComponent {
  fileData: any = null;
  uploadedFilePath: string = null;
   formData = new FormData();
    reader = new FileReader();
  @Output() fiLoaded: EventEmitter<File> = new EventEmitter();
  constructor(private pointeService: PointeService) { }

  fileProgress(fileInput: any) {

    this.fileData = fileInput.target.files[0];

    this.reader.readAsDataURL(this.fileData);
    this.reader.onloadend = (_event) => {
      this.formData.append('file', this.fileData);
      this.onFileLoaded(this.formData);
    };
  }

  onFileLoaded(formData: any) {
    this.pointeService.postModifiedFileExel(formData)
      .subscribe(events => {
        if (events.type === HttpEventType.UploadProgress) {
        } else if (events.type === HttpEventType.Response) {
         // this.fileUploadProgress = 0;
          console.log(events.body);
          alert('SUCCESS !!');
        }

      });
  }
}

Service

postModifiedFileExel(formData: any) {
    return this.http.post(`${AppUtils.REST_API_SERVER}/espacegroupe/upload-file`, formData ,  {
      reportProgress: true,
      observe: 'events'
    });
  }

I also noticed that my post contains just the name of the file and it does not cotains data in byte format

enter image description here

Any suggestions please?


Solution

  • For those who still stuck in the same issue, i will first explain how i debugged to find out the solution, and second what i was doing wrong.

    Debugging

    When i flowed the stack trace i found two methods that are responsible for the message that i receive i.e Current request is not a multipart request

    public class ServletFileUpload extends FileUpload {
            private static final String POST_METHOD = "POST";
    
            public static final boolean isMultipartContent(HttpServletRequest request) {
                return !"POST".equalsIgnoreCase(request.getMethod()) ? false : FileUploadBase.isMultipartContent(new ServletRequestContext(request));
            }
          .....
    }
    

    and

        public abstract class FileUploadBase {
    
            public FileUploadBase() {
            }
    
            public static final boolean isMultipartContent(RequestContext ctx) {
                String contentType = ctx.getContentType();
                if (contentType == null) {
                    return false;
                } else {
                    return contentType.toLowerCase(Locale.ENGLISH).startsWith("multipart/");
                }
            }
         ....
    }
    

    This means that if your call is different of POST or your content type does not start with "multipart/" your playload is considered as a non multipart

    and i noticed that my content Type was alway Content-Type: application/json

    But why do i always have Content-Type: application/json althought formData is supposed to be Content-Type: multipart/form-data ?

    In my case it was because in the application there is an url interceptor that always sets in the header Content-Type: application/json.

    const authReq = req.clone({setHeaders: {'Content-Type': 'application/json'}, withCredentials: true});
    

    To be sure that you send the right data type, be sure that in request Header you have Content-Type: multipart/form-data;boundary=... and that your formData is in binary.

    enter image description here

    Here there is a link to the article that helped me to resolve this issue