Tomcat: ExceptionHasndler doesn't work for Mul

2019-08-19 08:43发布

问题:

I have controller like this:

@PostMapping("/rest_upload1")
public ResponseEntity upload1(@RequestParam("file") MultipartFile multipartFile) throws IOException {
  throw new IllegalArgumentException();
}

and in configuration I have settings:

spring.http.multipart.max-file-size=100MB
spring.http.multipart.max-request-size=100MB

it means that spring will throw MultipartException in case if file exceeds 100MB.

To handle this exception I wrote handler:

@ControllerAdvice
public class RestExceptionHandlerAdvice extends ResponseEntityExceptionHandler {

    @ExceptionHandler(MultipartException.class)
    @ResponseBody
    public ResponseEntity<ApiError> handleException(MultipartException e) {
         logger.warn("MultipartException:", e);
         ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST,
                String.valueOf(HttpStatus.BAD_REQUEST),
                ExceptionUtils.getRootCauseMessage(e),
                Collections.emptyList());
        return new ResponseEntity<ApiError>(apiError, HttpStatus.BAD_REQUEST);        
    }

In case of error this code invokes(i see it in debug)

but in browser I don't see response:

I googled a lot of time and looked loke everuthing ok. And I tried to add handler for IllegalArgumentException:

@ExceptionHandler(IllegalArgumentException.class)
@ResponseBody
public ResponseEntity<ApiError> handleException(IllegalArgumentException e) {

    ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST,
                String.valueOf(HttpStatus.BAD_REQUEST),
                ExceptionUtils.getRootCauseMessage(e),
                Collections.emptyList());

    return new ResponseEntity<ApiError>(apiError, HttpStatus.BAD_REQUEST);            
}

And I upload file less than 100mb. At this case result differs:

But anyway response code is wrong.

What can be wrong?

P.S.

I tried:

@ExceptionHandler(MultipartException.class)
@ResponseStatus(value = HttpStatus.PAYLOAD_TOO_LARGE)
@ResponseBody
public String handleException(MultipartException e) {
    return ExceptionUtils.getRootCauseMessage(e);      
}

it looks like the same as here:

How to handle maximum file size Exception in Spring Boot?

P.S.2

I found workaround but it looks like bug in sring:

I added dependencies:

compile "org.apache.commons:commons-io:1.3.2"
compile "commons-fileupload:commons-fileupload:1.3.3"

register beans:

@Bean
public MultipartResolver multipartResolver() {
    CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
     multipartResolver.setMaxUploadSize(10);
     return multipartResolver;
}

and wrote:

@ControllerAdvice
public class UploadExceptionHandler {
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    @ResponseStatus(HttpStatus.PAYLOAD_TOO_LARGE)
    @ResponseBody
    public String handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
        return e.getMessage();
    }
}

回答1:

Not very clever tomcat developers added new feature which we need to disable/override.

It is working after I have added:

    @Bean
    public TomcatEmbeddedServletContainerFactory tomcatEmbedded() {

        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();

        tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {

            // connector other settings...

            // configure maxSwallowSize
            if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {
                // -1 means unlimited, accept bytes
                ((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
            }

        });

        return tomcat;

    }