Man*_*tha 5 spring file-upload multipartform-data spring-mvc spring-boot
spring boot
我有一个文件上传 api,在该版本下工作得很好2.1.13
。版本升级到 后2.5.2
,开始抛出异常。查看更改日志,我看不到任何与处理相关的重大更改Multipart
。我在这里可能会缺少什么?以下是我的示例代码。
例外
org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
at org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver.resolveArgument(RequestPartMethodArgumentResolver.java:161) ~[spring-webmvc-5.3.8.jar:5.3.8]
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121) ~[spring-web-5.3.8.jar:5.3.8]
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:170) ~[spring-web-5.3.8.jar:5.3.8]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-5.3.8.jar:5.3.8]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106) ~[spring-webmvc-5.3.8.jar:5.3.8]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894) ~[spring-webmvc-5.3.8.jar:5.3.8]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.8.jar:5.3.8]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.8.jar:5.3.8]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1063) ~[spring-webmvc-5.3.8.jar:5.3.8]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.8.jar:5.3.8]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) [spring-webmvc-5.3.8.jar:5.3.8]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) [spring-webmvc-5.3.8.jar:5.3.8]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) [tomcat-embed-core-9.0.48.jar:4.0.FR]
Run Code Online (Sandbox Code Playgroud)
应用程序属性
spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=20MB
spring.servlet.multipart.max-request-size=20MB
Run Code Online (Sandbox Code Playgroud)
控制器端点
@PostMapping(
value = "/upload",
consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
public ResponseEntity<Object> uploadFile(@RequestPart("file") MultipartFile file) {
...
}
Run Code Online (Sandbox Code Playgroud)
请求有效负载样本
POST http://localhost:8080/upload
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryGG9dgUb5THDV0eDB
------WebKitFormBoundaryGG9dgUb5THDV0eDB
Content-Disposition: form-data; name="file"; filename="Sample.pdf"
Content-Type: application/pdf
------WebKitFormBoundaryGG9dgUb5THDV0eDB--
Run Code Online (Sandbox Code Playgroud)
注意:MultipartResolver
我的配置中没有定义任何bean。我尝试按如下方式添加 MultipartResolver bean 定义(一次仅一个),但似乎没有解决问题。
@Bean
public CommonsMultipartResolver multipartResolver() { // didn't work
return new CommonsMultipartResolver();
}
@Bean
public StandardServletMultipartResolver multipartResolver() { // didn't work
return new StandardServletMultipartResolver();
}
Run Code Online (Sandbox Code Playgroud)
Man*_*tha 11
事实证明,这个问题是在Spring Boot 2.2
. HttpHiddenMethodFilter
从该版本开始,默认情况下禁用过滤器。启用过滤器后,问题得到解决application.properties
。
spring.mvc.hiddenmethod.filter.enabled=true
Run Code Online (Sandbox Code Playgroud)
我的详细发现
上述过滤器的目的与我收到的错误无关。但是请求parts
被初始化作为执行过滤器的副作用。更具体地说,当过滤器尝试检索_method
参数值时(e.g. request.getParameter("_method")
,实例getParameter
的方法request
在内部似乎会解析参数,然后初始化请求parts
。所以2.2版本禁用过滤器后spring-boot
,就没有什么可以初始化请求了parts
。
我觉得请求parts
初始化应该在Spring
框架本身内修复。但在那之前,我们要么可以启用HttpHiddenMethodFilter
过滤器,要么可以定义一个自定义过滤器来负责初始化请求parts
,如下所示:
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class RequestInitializerFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
request.getParameterNames(); // this takes care of initializing request `parts`
filterChain.doFilter(request, response);
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
8667 次 |
最近记录: |