无法让Spring Boot延迟解析多部分文件 [英] Cannot get Spring Boot to lazily resolve a multipart file

查看:140
本文介绍了无法让Spring Boot延迟解析多部分文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用Spring Initializr创建了一个Spring Boot 2演示应用程序,并在下面添加了控制器:

I have created a Spring Boot 2 demo application with the Spring Initializr and added the controller below:

@Controller
@RequestMapping("/demo")
public class UploadController {
    private final static Logger LOG =   LoggerFactory.getLogger(UploadController.class);

    @PostMapping("/upload")
    public ResponseEntity<String> uploadFile(
        @RequestParam("metadata") MultipartFile metadata,
        @RequestParam("payload") MultipartFile payload) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        Map metadataMap = mapper.readValue(metadata.getInputStream(), Map.class);
        LOG.info("Received call to upload file {}", metadataMap.get("filename"));
        LOG.info("File size: {}", payload.getBytes().length);
        LOG.info("File {} successfully uploaded", metadataMap.get("filename"));
        return ResponseEntity.ok().build();
    }

}

然后我添加了一个包含以下配置的application.yaml文件:

I then added an application.yaml file containing this configuration:

spring:
  servlet:
    multipart:
      max-file-size: 2000000MB
      max-request-size: 2000000MB  
      resolve-lazily: true

我的目标是让控制器解析并记录metadata文件,然后再开始读取payload文件,但是resolve-lazily设置似乎被Boot忽略:控制器内部的代码不会执行直到读取整个身体.

My goal is to have the controller parse and log the metadata file before it starts reading the payload file, but the resolve-lazily setting seems to be ignored by Boot: the code inside the controller won't be executed until the whole body is read.

我使用下面的命令来测试控制器:

I use the command below to test the controller:

curl -F metadata=@metadata.json -F payload=@payload.bin http://localhost:8080/demo/upload

我的代码/配置有什么问题吗?我能正确理解设置的含义吗?

Is there anything wrong with my code/configuration? Am I getting the meaning of the setting right?

推荐答案

目前,如果您想避免一次读取(并缓冲)整个身体,我想您将必须提供自己的解析器,如此处中所述.真正有趣的(但通常是不必要的)是以新的MultipartResolver实现的形式实现的.

At present, if you want to avoid reading (and buffering) the whole body all at once, I think you will have to provide your own parser, as described in the answers here. What would be really interesting (but generally unnecessary) would be to do so in the form of a new MultipartResolver implementation.

有两个针对接口MultipartResolver ,并且都提供了功能setResolveLazily(boolean)(

There are two existing implementations documented for interface MultipartResolver, and both supply a function setResolveLazily(boolean) (standard), (commons). I have tried with both, and neither seem to allow for parsing or streaming multipart files or parameters independently.

默认为"false",立即解析multipart元素,并在resolveMultipart(javax.servlet.http.HttpServletRequest)调用时引发相应的异常.将其切换为"true"以进行延迟的多部分解析,一旦应用程序尝试获取多部分文件或参数,则抛出解析异常.

Default is "false", resolving the multipart elements immediately, throwing corresponding exceptions at the time of the resolveMultipart(javax.servlet.http.HttpServletRequest) call. Switch this to "true" for lazy multipart parsing, throwing parse exceptions once the application attempts to obtain multipart files or parameters.

尽管在文档中说了什么,但我发现一旦调用resolveMultipart,就会在调用返回之前对整个正文进行解析和缓冲.我知道这一点是因为我可以观看正在创建的临时文件.

Despite what it says in the documentation, I have found that once you call resolveMultipart, the entire body is parsed and buffered before the call returns. I know this because I can watch the temp-files being created.

关于我的代码有什么问题"的注释...

One note about "Is there anything wrong with my code"...

答案:是的,因为通过使用@RequestParam,您曾间接要求Spring在调用控制器之前提前解析参数.相反,如果文档正确,您应该能够做的是从控制器内部独立地请求参数:

Answer: Yes, because by using @RequestParam you have indirectly asked Spring to resolve your parameters ahead of time, before your controller is ever called. What you should be able to do instead (if the documentation were correct) is request the parameters independently from inside your controller:

配置(application.properties):

Configuration (application.properties):

spring.servlet.multipart.enabled = true
spring.servlet.multipart.resolve-lazily = true

控制器:

@PostMapping(path = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Void> postUpload(HttpServletRequest rawRequest) {

    multipartResolver.setResolveLazily(true); // unclear why this is exists
    MultipartHttpServletRequest request = multipartResolver.resolveMultipart(rawRequest);

    String p1 = request.getParameter("first-parameter");
    String p2 = request.getParameter("second-parameter");
    System.out.println("first-parameter="+p1+", second-parameter"+p2);

    multipartResolver.cleanupMultipart(request);
    return new ResponseEntity<Void>(HttpStatus.ACCEPTED);
}


我发现的resolve-lazily的一个有用方面是,它允许您为某些rest控制器编写自己的解析器,而对其他控制器使用内置解析器(请参阅我的答案其他建议,这是一个小突破.


One useful aspect of resolve-lazily that I have discovered is that it allows you to write your own parser for some rest controllers while using the built-in parser for others (see my answer here). In other words, you don't have to use spring.servlet.multipart.enabled = false to get your parser to work. This is a minor breakthrough relative to other advice that I had seen previously.

这篇关于无法让Spring Boot延迟解析多部分文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆