问题
I'm running the complete version of Spring boot Upload file guide at Spring Guide, but I used Undertow as embedded servlet instead of Tomcat default. And it worked.
When I try to upload file with size larger than the value in config file
spring.http.multipart.max-file-size=128KB
spring.http.multipart.max-request-size=128KB
It raises exception. That is expected behavior
With Tomcat embedded servlet, it can be easily handled by catching SizeLimitExceededException
or MultipartException
But with Undertow, it throws RuntimeException event I catch it in global handler:
@ControllerAdvice
public class GlobalControllerExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler({RuntimeException.class, Exception.class, IOException.class})
ResponseEntity<?> handleControllerException(Exception exc, HttpServletRequest request, Throwable ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
The Exception message:
java.lang.RuntimeException: java.io.IOException: UT000020: Connection terminated as request was larger than 131072
at io.undertow.servlet.spec.HttpServletRequestImpl.parseFormData(HttpServletRequestImpl.java:779) ~[undertow-servlet-1.4.20.Final.jar:1.4.20.Final]
at io.undertow.servlet.spec.HttpServletRequestImpl.getParameter(HttpServletRequestImpl.java:653) ~[undertow-servlet-1.4.20.Final.jar:1.4.20.Final]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:75) ~[spring-web-4.3.12.RELEASE.jar:4.3.12.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.3.12.RELEASE.jar:4.3.12.RELEASE]
Here is the codes:
The controller
@PostMapping("/")
public String handleFileUpload(@RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
storageService.store(file);
redirectAttributes.addFlashAttribute("message",
"You successfully uploaded " + file.getOriginalFilename() + "!");
return "redirect:/";
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-uploading-files</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>1.3.0.RELEASE</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Anyone get the same problem with me? How can I catch the exception when maximum file size upload is exceeded?
Any help would be greatly appreciated
回答1:
Maybe it is able to help in some particular case.
I have the same problem with undertow and exception handling.
My case is a little bit different, I also have spring-security, so the exceptions like RequestTooBigException
are caused in spring-security filters when some of them try to read information from the request.
As a solution, I use an additional filter that is added before the first security filter that is caused that exception. (For my it is BearerTokenAuthenticationFilter.class
)
There is an additional filter that handles these exceptions:
@Component
@Slf4j
public class SecurityRequestToBigExceptionHandlerFilter extends OncePerRequestFilter {
@Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
try {
filterChain.doFilter(request, response);
} catch (IllegalStateException | RequestTooBigException | MultiPartParserDefinition.FileTooLargeException ex) {
if (ex instanceof RequestTooBigException
|| ex instanceof MultiPartParserDefinition.FileTooLargeException) {
writeResponse(response, ex);
return;
}
Throwable causeException = ex.getCause();
if (nonNull(causeException)
&& (causeException instanceof RequestTooBigException
|| causeException instanceof MultiPartParserDefinition.FileTooLargeException)) {
writeResponse(response, causeException);
return;
}
throw ex;
}
}
private void writeResponse(HttpServletResponse response, Throwable ex) throws IOException {
log.debug("Handle RequestToBig Exception with {}", ex.getMessage());
response.setStatus(HttpStatus.BAD_REQUEST.value());
response.getWriter().write(ex.getMessage());
}
}
Next what we need to change is security configuration.
There is my simplified security config:
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private final SecurityRequestToBigExceptionHandlerFilter requestToBigExceptionHandlerFilter;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(requestToBigExceptionHandlerFilter, BearerTokenAuthenticationFilter.class)
.csrf().disable()
.cors()
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2ResourceServer().jwt();
}
}
来源:https://stackoverflow.com/questions/46968098/undertow-throws-runtimeexception-when-uploading-multipart-file-exceeding-the-set