Spring Boot中@ControllerAdvice无法捕获自定义文件上传异常
我使用@RestControllerAdvice实现了全局异常处理器,能够正常捕获NoSuchElementFoundException等自定义异常,未捕获的错误会被handleAllUncaughtException方法捕获。但我创建了MaxUploadSizeExceededException和FileSizeLimitExceededException两个自定义异常类及对应的处理方法,却无法捕获文件上传大小超限的错误,该错误仍被handleAllUncaughtException捕获。
相关代码示例
@RestControllerAdvice public class DefaultExceptionHandler extends ResponseEntityExceptionHandler { // 处理NoSuchElementFoundException @ExceptionHandler(NoSuchElementFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public ResponseEntity<Object> handleNoSuchElementFoundException(NoSuchElementFoundException ex, WebRequest request) { log.error(FAILED_TO_FIND_ELEMENT, ex); return buildErrorResponse(ex, HttpStatus.NOT_FOUND, request); } // 尝试捕获自定义文件大小超限异常的方法 @ExceptionHandler(MaxUploadSizeExceededException.class) @ResponseStatus(HttpStatus.PAYLOAD_TOO_LARGE) public ResponseEntity<Object> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException ex, WebRequest request) { return buildErrorResponse(ex, HttpStatus.PAYLOAD_TOO_LARGE, request); } @ExceptionHandler(FileSizeLimitExceededException.class) @ResponseStatus(HttpStatus.PAYLOAD_TOO_LARGE) public ResponseEntity<Object> handleFileSizeLimitExceededException(FileSizeLimitExceededException ex, WebRequest request) { return buildErrorResponse(ex, HttpStatus.PAYLOAD_TOO_LARGE, request); } // 兜底处理所有未捕获的异常 @ExceptionHandler(Exception.class) @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) public ResponseEntity<Object> handleAllUncaughtException(Exception ex, WebRequest request) { return buildErrorResponse(ex, UNKNOWN_ERROR, HttpStatus.INTERNAL_SERVER_ERROR, request); } // 省略其他代码 }
自定义异常类示例
public class MaxUploadSizeExceededException extends RuntimeException { public MaxUploadSizeExceededException(String message) { super(message); } }
错误堆栈跟踪显示抛出的是org.springframework.web.multipart.MaxUploadSizeExceededException,针对问题解答如下:
1. 应使用哪种异常类型创建自定义类,并如何在自定义方法中捕获该错误?
你当前的自定义MaxUploadSizeExceededException与Spring内置的org.springframework.web.multipart.MaxUploadSizeExceededException是完全独立的两个类,所以你的异常处理器无法匹配到实际抛出的内置异常。有两种解决方式:
方式一:直接捕获Spring内置异常
无需自定义同名异常类,直接在@ExceptionHandler中指定Spring内置的异常类型即可:
@ExceptionHandler(org.springframework.web.multipart.MaxUploadSizeExceededException.class) @ResponseStatus(HttpStatus.PAYLOAD_TOO_LARGE) public ResponseEntity<Object> handleSpringMaxUploadSizeExceededException(org.springframework.web.multipart.MaxUploadSizeExceededException ex, WebRequest request) { return buildErrorResponse(ex, HttpStatus.PAYLOAD_TOO_LARGE, request); }
方式二:自定义异常并手动抛出
如果坚持使用自定义异常,需要在文件上传逻辑中捕获Spring内置异常,再手动抛出自己的自定义异常:
- 保留你已定义的
MaxUploadSizeExceededException类 - 在文件上传的Controller方法中处理:
@PostMapping("/upload") public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) { try { // 执行文件上传逻辑 } catch (org.springframework.web.multipart.MaxUploadSizeExceededException ex) { throw new MaxUploadSizeExceededException("文件大小超过限制"); } }
这样自定义异常处理器就能匹配到你手动抛出的异常了。
2. 使用HTTP状态码PAYLOAD_TOO_LARGE是否正确?
完全正确。HttpStatus.PAYLOAD_TOO_LARGE对应的是HTTP 413状态码,该状态码的语义就是请求体过大,完全契合文件上传大小超限的场景。
内容的提问来源于stack exchange,提问作者user19601508

