【问题标题】:Spring Boot File Upload - part is null after upgrade to Spring Boot 2.4Spring Boot 文件上传 - 升级到 Spring Boot 2.4 后部分为空
【发布时间】:2021-12-21 14:05:49
【问题描述】:

我使用类似于以下 curl 变体的上传请求的分段文件上传:

curl --request POST 'http://localhost:8080/api/upload' --form 'csv=@"/path/file.csv"'

在浏览器中查看表单数据如下:

------WebKitFormBoundarysT6cYRLsXHQ8EWtZ
Content-Disposition: form-data; name="csv"; filename="file.csv"
Content-Type: text/csv
------WebKitFormBoundarysT6cYRLsXHQ8EWtZ--

我的 Java 代码如下所示:

@PostMapping(value = "/api/upload")
public ResponseEntity<String> upload(@RequestBody MultipartFile csv) {
    System.out.println(new String(csv.getBytes(), StandardCharsets.UTF_8));
    return ResponseEntity.ok().body(null);
}

它曾经在 Spring Boot 2.0 上运行良好,但一旦我升级到 Spring Boot 2.4/2.5,csv 参数始终为空,因此csv.getBytes() 抛出 NullPointerException。

到目前为止我已经尝试过:

  • @RequestBody 更改为 @RequestPart("csv")@RequestParam("csv") 会使上传请求返回 HTTP 400 代码,并显示消息“必需的请求部分 'csv' 不存在”
  • consumes = MediaType.MULTIPART_FORM_DATA_VALUE 添加到@PostMapping 没有任何区别。

我发现默认情况下 Spring Boot 使用 StandardServletMultipartResolver,因为 MultipartAutoConfiguration 已启用,可以在这里看到 - https://github.com/spring-projects/spring-boot/blob/v2.4.13/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/servlet/MultipartAutoConfiguration.java

我找到了一种解决方法 - 添加 CommonsMultipartResolver 作为默认解析器而不是 StandardServletMultipartResolver 可以解决问题。这可以通过添加新的依赖项和相应的 bean 来完成:

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.4</version>
</dependency>

@Bean(name = "multipartResolver")
public CommonsMultipartResolver multipartResolver() {
    return new CommonsMultipartResolver();
}

但是 Spring 不鼓励使用 CommonsMultipartResolver,如 https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.spring-mvc.multipart-file-uploads 所示

建议使用容器的内置支持 分段上传,而不是引入额外的依赖 例如 Apache Commons 文件上传。

这就是我想使用内置支持的原因。任何想法如何解决它?

【问题讨论】:

  • 尝试https://www.baeldung.com/spring-file-upload,第 7 节。Spring Boot 文件上传
  • 你有 spring-boot-starter-web 依赖吗?我正在使用 @RequestParam(value = "csv") MultipartFile 文件,它工作正常
  • @MarcStroebel 谢谢,但是 spring-boot-starter-web 和 spring.servlet.multipart.enabled 都已经就位了。
  • @DeepanshuRathi 确实我的项目中已经有了这个依赖项。
  • @lagivan 我遇到了同样的问题:在 Spring 从 2.3.5.RELEASE 升级到 2.6.2 之后,“必需的请求部分 'myFileName' 不存在”。有关使其与 StandardServletMultipartResolver 一起使用的任何消息?

标签: java spring spring-boot


【解决方案1】:

在身份验证过滤器之前添加过滤器为我解决了问题。与 StandardServletMultipartResolver 一起使用

public class HttpRequestPartsInitFilter extends OncePerRequestFilter {

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
    if(StringUtils.startsWithIgnoreCase(request.getContentType(), "multipart/")) {
        if (request.getParts().isEmpty()) {
            log.info("Request.getParts() is empty for={}", request.getPathInfo());
        } else {
            log.info("Request.getParts() is NOT empty for={}", request.getPathInfo());
        }
    }
    filterChain.doFilter(request, response);
}

}

我在扩展 WebSecurityConfigurerAdapter 的安全 @Configuration 类中注册了过滤器

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .addFilterBefore(new OktaErrorFilter(LOGIN_URL, OKTA_ERROR_URL),
                        OAuth2AuthorizationRequestRedirectFilter.class)
                .addFilterBefore(new HttpRequestPartsInitFilter(), OktaErrorFilter.class)
                ....        }

我找不到解释为什么这使它起作用。 这里提到的类似修复: Spring POST multipart/form-data, request parts always empty

【讨论】:

    猜你喜欢
    • 2021-02-25
    • 2014-10-31
    • 2022-12-22
    • 2014-05-01
    • 1970-01-01
    • 2022-08-24
    • 2021-01-18
    • 2022-01-18
    • 1970-01-01
    相关资源
    最近更新 更多