Spring文件上传内容类型验证,总是八位字节流?

Posted

技术标签:

【中文标题】Spring文件上传内容类型验证,总是八位字节流?【英文标题】:Spring file upload content type validation, always octet-stream? 【发布时间】:2016-01-25 09:32:51 【问题描述】:

我正在尝试在我的 Restful Spring Boot 应用程序中实现 pdf 文件上传。

我有以下方法;

@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 只是 MultipartFile 的一个包装器。

然后我使用 Postman 通过 form-data body 'file'=<filename.pdf> 发布请求

上面 printlns 中的内容类型是 ALWAYS octet-stream。无论我发送什么类型的文件(png、pdf 等),它始终是八位字节流。如果我在 Postman 中专门将 application/pdf 设置为 Content-Type 标头,则 FileDTO 中的 MultipartFile 最终为 null。

问题是,我的 Spring Controller 方法有问题,还是 Postman 没有正确构建请求?

如果 Postman 无法正确获取 Content-Type,我是否可以期望实际的客户端应用程序将内容类型正确设置为 pdf?

【问题讨论】:

【参考方案1】:

您是否尝试过 Apache Tika 库来检测上传文件的 mime 类型?

Kotlin 中的代码示例

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

【讨论】:

你在跟踪我吗?你在我窗外吗? 2 年多没看这个问题了,就在昨天,我回到这部分代码并决定扩展文件类型支持,经过多次谷歌搜索,最终找到了 Tika,它对我的​​帮助无穷无尽!但是几个小时后,我收到了一封 SO 电子邮件,通知我这个旧问题已经更新,而你的建议是一样的?? ......你是......你是谷歌吗? 大声笑,当然不是,我什至不知道你是谁:) 今天我在工作中一直在处理这部分代码【参考方案2】:

FileDTO 将包装multipart/form-data 的全部内容,因此如果您上传的文件输入名为file,您的 DTO/Form/POJO 应该类似于:

class FileDTO

  @NotNull
  private String anotherAttribute;

  @NotNull
  private MultipartFile file;

  //Getters and Setters

因此,您还应该将控制器功能更改为

@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 ...

要使用此类功能,您应该在 MVC 配置文件中使用 StandardServletMultipartResolver。比如:

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

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

我希望它适合你。

【讨论】:

【参考方案3】:

通常文件上传以 MIME 多部分消息格式包装,因此 HTTP 标头中的内容类型只能为 multipart/form-data,并且您在每个部分中分别指定每个字段(包含文件)的 MIME 类型。

在 Postman 中似乎没有办法为多部分字段指定 MIME 类型,所以我只能假设它是一个缺失的功能。

【讨论】:

【参考方案4】:

我之前遇到过这个问题,使用以下解决了这个问题:

Files.probeContentType(path)

上面返回一个带有格式类型的字符串。似乎是我尝试过的最可靠的解决方案。

【讨论】:

以上是关于Spring文件上传内容类型验证,总是八位字节流?的主要内容,如果未能解决你的问题,请参考以下文章

从安卓手机上传图像类型应用程序/八位字节流

Spring Boot - RabbitMQ - 将消息内容类型从八位字节流更改为 json

MIME、八位字节流和 Uploadify

从手机上传文件发送应用程序/八位字节流

文件上传错误“应用程序/八位字节流”

Spring Android POST在ResponseEntity中没有返回类型应用程序/八位字节流