Spring Boot-流式Apache FileUpload-流意外终止

时间:2018-07-03 07:45:59

标签: java spring spring-boot inputstream apache-commons-fileupload

我正在尝试将Apache Streaming API与Spring Boot(禁用的Spring Multipart解析器)一起使用。但是,当我尝试将InputStream转换为byte []时,出现了异常-流意外终止。知道什么地方出错了吗? 代码示例:

//Server side code - Spring Boot REST Controller
@PostMapping
public ResponseEntity<MyObjectDto> upload(HttpServletRequest request)
    {
    FileItemIterator itemIterator;
    MyObject myObject=null;
    if (!ServletFileUpload.isMultipartContent(request)) {
        throw new RuntimeException("Invalid content passed for upload");
    }
    ServletFileUpload servletFileUpload = new ServletFileUpload();
    itemIterator = servletFileUpload.getItemIterator(request);
    while (itemIterator.hasNext()) {
        FileItemStream fileItem = itemIterator.next();
        InputStream inputStream = fileItem.openStream();
        if (!fileItem.isFormField()) {
            byte[] bytes = IOUtils.toByteArray(inputStream);
           //...Pass bytes for further processing
           myObject =doSomething(bytes)
        }
    } 
    return ResponseEntity.ok(Mapper.map(myObject));
}


//Spring  multipart - disabled
spring.http.multipart.enabled=false

// Client code using Apache Streaming API

Request.Post(uri)
              .body(buildMultipartEntityNew(FileUtils.openInputStream(new File("src/test/resources/my.pdf"))))
              .execute()
              .handleResponse(responseHandler);

// Multipart Entity Builder
private static HttpEntity buildMultipartEntity(InputStream inputStream) throws JsonProcessingException {

    return MultipartEntityBuilder.create()
                                 .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
                                 .addBinaryBody("file", inputStream,
                                                ContentType.APPLICATION_OCTET_STREAM,
                                                "teamfile")
                                .build();
}

例外:

  

org.apache.commons.fileupload.MultipartStream $ MalformedStreamException:   流意外结束   org.apache.commons.fileupload.MultipartStream $ ItemInputStream.makeAvailable(MultipartStream.java:1005)   在   org.apache.commons.fileupload.MultipartStream $ ItemInputStream.read(MultipartStream.java:903)   在java.io.InputStream.read(InputStream.java:101)在   org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2146)在   org.apache.commons.io.IOUtils.copy(IOUtils.java:2102)在   org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2123)在   org.apache.commons.io.IOUtils.copy(IOUtils.java:2078)在   org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:721)

1 个答案:

答案 0 :(得分:0)

我发现了问题。如果有人遇到类似问题,首先要检查的是链中的任何过滤器都在尝试包装/重构请求(包含输入流)。如果您知道确切的过滤器,可以将其禁用

 @Bean
    public FilterRegistrationBean registration(PreAuthenticationFilter filter) {
      FilterRegistrationBean registration = new FilterRegistrationBean(filter);
      registration.setEnabled(false);
      return registration;
}

或者您可以通过全部禁用它们进行测试

    public class DefaultFiltersBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory bf)
        throws BeansException {
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)bf;

        Arrays.stream(beanFactory.getBeanNamesForType(javax.servlet.Filter.class))
              .forEach(
                  name -> {
                      BeanDefinition definition =
                          BeanDefinitionBuilder.genericBeanDefinition(FilterRegistrationBean.class)
                                               .setScope(BeanDefinition.SCOPE_SINGLETON)
                                               .addConstructorArgReference(name)
                                               .addConstructorArgValue(new ServletRegistrationBean[] {})
                                               .addPropertyValue("enabled", false)
                                               .getBeanDefinition();

                      beanFactory.registerBeanDefinition(name + "FilterRegistrationBean", definition);
                  });
    }
}

在我的情况下,自定义安全过滤器正在分解请求并重建输入流,并且它仅部分重建了输入流,因此产生了错误-MalformedStream。

我通过尝试这些选项来达到目的

  1. 禁用所有安全性

security:
  basic:
   enabled: false
management:
  security:
   enabled: false

  1. 删除自动配置的Springs默认安全性

spring:
 autoconfigure:
   exclude: org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration

一旦我知道安全是问题所在。我仅为输入流禁用了POST的安全性,而输入流却毫发无损。

 @Override public void configure(WebSecurity web) throws Exception {
    web.ignoring()
       .requestMatchers(ignoreNonJsonMediaTypes())
       .and()
       .ignoring()
       .antMatchers(HttpMethod.POST);

    super.configure(web);
}

private MediaTypeRequestMatcher ignoreNonJsonMediaTypes() {
    MediaTypeRequestMatcher
        matcher =
        new MediaTypeRequestMatcher(new HeaderContentNegotiationStrategy(), MediaType.APPLICATION_JSON);
    matcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
    return matcher;
}