【问题标题】:spring boot multipartFile with application/octet-stream throws exception带有 application/octet-stream 的 spring boot multipartFile 抛出异常
【发布时间】:2017-03-08 22:14:42
【问题描述】:

我想使用 Spring boot 构建一个简单的 Rest api,它接受任何给定的文件,然后对其执行一些操作。我浏览了 multipartFile https://spring.io/guides/gs/uploading-files/ 上的 spring 示例,并决定采用相同的方法。将通过我的 rest api 上传的文件将具有一些特定的扩展名。因此,我将内容类型指定为 application/octet-stream 。当我尝试运行相同的单元测试用例时, 我总是得到例外

nested exception is org.springframework.web.multipart.MultipartException: The current request is not a multipart request

如果内容类型为 text/plain 或 requestMapping 中没有“consumes”参数,则不会出现此异常。

我的控制器代码如下:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;

@Controller
@RequestMapping("/v1/sample")
public class SampleController {

    private static Logger log = LoggerFactory.getLogger(SampleController.class);

    @RequestMapping(path = "/{id}/upload",
                    consumes = {MediaType.APPLICATION_OCTET_STREAM_VALUE},
                    method = RequestMethod.POST)
    public ResponseEntity<String> uploadfile(@PathVariable String id,
            @RequestParam("file") MultipartFile upgradeFile) {
        log.info("Obtained a upload request for the id {}",id );
        return new ResponseEntity<String>("file upload has been accepted.",
                HttpStatus.ACCEPTED);
    }

}

我的单元测试sn-p如下:

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import com.stellapps.devicemanager.fota.Application;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@SpringApplicationConfiguration(classes = Application.class)
@EnableWebMvc
public class ControllerTest {

    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc mockMvc;

    @Before
    public void mockMvcBuilder() {
        this.mockMvc = webAppContextSetup(webApplicationContext).build();
    }

    @Test
        public void test_ValidPayload() {
            String uri = "/v1/sample/1234/upload";
            Path path = Paths.get("src/test/resources/someFile");
            try {
                byte[] bytes = Files.readAllBytes(path);
                 MockMultipartFile multipartFile =
                            new MockMultipartFile("file", "someFile.diff", "application/octet-stream", bytes);
                 mockMvc.perform(fileUpload(uri).file(multipartFile).contentType(MediaType.APPLICATION_OCTET_STREAM_VALUE))
                    .andExpect(status().isAccepted());
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
}

如果我使用 text/plain 作为内容类型并且我提供一个普通的文本文件,它可以正常运行。如果我将内容类型添加为 application/octet-stream 它会引发以下异常

    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: org.springframework.web.multipart.MultipartException: The current request is not a multipart request
    at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.assertIsMultipartRequest(RequestPartMethodArgumentResolver.java:204)
    at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.resolveArgument(RequestPartMethodArgumentResolver.java:129)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:99)
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:817)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:731)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:968)

我如何让我的请求接受 application/octet-stream 以及我应该对测试用例进行哪些更改以确保它成功。

更新:

删除消费头并且不指定 MockPartFile 中的内容类型是上传文件的方法之一。我想默认情况下控制器将其作为 application/octet-stream

更新:

感谢您的回复。我使用的是早期版本的spring(1.3.1),在完成答案后,我更新了我的spring版本和测试用例以匹配它,它开始工作了。

【问题讨论】:

  • 请提供minimal reproducible example。您的MockMvc 是如何设置的?您的多部分配置是什么样的?
  • 另外,你为什么期待一个错误的请求?此处有些内容未检查,请使用要求的详细信息编辑您的问题。

标签: java spring spring-mvc spring-boot


【解决方案1】:

试试下面的步骤

  • 从 RequestMapping 属性中移除 consumes
  • MockMultipartFile multipartFile = new MockMultipartFile("file","somename","multipart/form-data", fileinputstream);
  • 更改为 MockMvc:

    mockMvc.perform(MockMvcRequestBuilders.fileUpload("/v1/sample/1234/payload")                
                .file(multipartFile)
                .andExpect(status().isOk());
    

寻求帮助检查 Upload file using Spring mvc and MockMVC

编辑:

我已经在您的场景中尝试了一个示例 spring-boot-rest 应用程序。似乎 application/octet-stream 没有问题。请检查我的回购 https://github.com/satya-j/boot-file-manager

【讨论】:

  • 这会有什么不同?以前出了什么问题,这些更改如何解决?
  • 我对这个问题的建议是基于我一直使用的文件上传机制。我所能做的就是指向link [链接]stackoverflow.com/a/33033540/7063373。大多数文件上传的场景是通过带有一些附加数据的表单提交,所以 multipart/form-data
  • 如果您认为某个帖子是重复的,请标记以将其关闭。你的回答目前没有任何信心。您没有解释为什么他们的代码/配置/任何东西都不起作用,也没有解释为什么您的建议会使它起作用。这是一个糟糕的答案。
  • @SotiriosDelimanolis 我同意,我是新来的。不知道标记,也没有充分探索。感谢您指出。你会建议我删除我的答案吗?
  • 首先,如果可以的话,我建议你改进它。见How do I write a good answer?。如果你不能/不知道,那么,当然,删除它。
猜你喜欢
  • 2014-06-08
  • 2016-09-26
  • 2019-09-19
  • 2013-04-12
  • 2017-09-17
  • 2014-07-16
  • 1970-01-01
  • 1970-01-01
  • 2020-08-24
相关资源
最近更新 更多