简体   繁体   中英

Spring file upload content type validation, always octet-stream?

I'm trying to implement pdf file uploading in my Restful Spring Boot application.

I have the following method;

@RequestMapping(value = FILE_URL, method = RequestMethod.POST)
public ResponseDTO submitPDF(
        @ModelAttribute("file") FileDTO file) {

    MediaType mediaType = MediaType.parseMediaType(file.getFile().getContentType());

    System.out.println(file.getFile().getContentType());
    System.out.println(mediaType);
    System.out.println(mediaType.getType());

    if(!"application/pdf".equals(mediaType.getType())) {
        throw new IllegalArgumentException("Incorrect file type, PDF required.");
    }

    ... more code here ...
}

FileDTO is just a wrapper around MultipartFile.

I'm then using Postman to POST the request with form-data body 'file'=<filename.pdf>

The content type in the printlns above is ALWAYS octet-stream. No matter what type of file I send in (png, pdf, etc) its always octet stream. If I specifically set application/pdf as Content-Type header in Postman the MultipartFile within FileDTO ends up as null.

Question is, is there something wrong with my Spring Controller method, or is the request just not being built correctly by Postman?

If Postman can't get the Content-Type right, can I expect actual client apps to properly set content type to pdf?

Have you tried Apache Tika library for detecting mime types of uploaded file?

Code Example in Kotlin

private fun getMimeType(file: File) = Tika().detect(file)

Normally file uploads are wrapped in a MIME multipart message format, so the content type in the HTTP header can only be multipart/form-data and you specify the MIME type of each field (include files) separately in each part.

It seems in Postman there's no way to specify the MIME type for a multi-part field so I can only assume it's a missing feature.

The FileDTO will wrap the whole content of the multipart/form-data so if your uploaded file input is named file , your DTO/Form/POJO should be alike to:

class FileDTO{

  @NotNull
  private String anotherAttribute;

  @NotNull
  private MultipartFile file;

  //Getters and Setters
}

Therefore you should also change your controller function to

@RequestMapping(value = FILE_URL, method = RequestMethod.POST)
public ResponseDTO submitPDF(@ModelAttribute FileDTO fileWrapper) {

    MediaType mediaType = MediaType.parseMediaType(fileWrapper.getFile().getContentType());

    System.out.println(fileWrapper.getFile().getContentType());
    System.out.println(mediaType);
    System.out.println(mediaType.getType());

    if(!"application/pdf".equals(mediaType.getType())) {
        throw new IllegalArgumentException("Incorrect file type, PDF required.");
    }

    ... more code here ...
}

To use this sort of functions you should use the StandardServletMultipartResolver in your MVC configurer file. Something like:

@EnableWebMvc
@Configuration
@ComponentScan("mypackage.web.etc")
public class WebMvcConfig extends WebMvcConfigurerAdapter{

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

I hope it suites you.

I've had this issue before, using the following fixed the issue:

Files.probeContentType(path)

The above returns a string with the format type. Seems to be the most reliable solution I've tried.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM