如何使用@ExceptionHandler 捕获HTTP 405 "Method Not Allowed" 异常?
How to catch HTTP 405 "Method Not Allowed" exception using @ExceptionHandler?
我创建了一个 REST 应用程序并添加了一个 class 来处理异常:
@RestControllerAdvice(basePackages = "com.foxminded.university.api.controller")
public class ApiGlobalExceptionHandler extends ResponseEntityExceptionHandler {
private static final String API_UNHANDLED_EXCEPTION = "REST API reached unhandled exception: %s";
private static final HttpStatus internalServerError = HttpStatus.INTERNAL_SERVER_ERROR;
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handle(Exception e) {
ExceptionDetail exceptionDetail = new ExceptionDetail(
String.format(API_UNHANDLED_EXCEPTION, e.getMessage()),
internalServerError,
ZonedDateTime.now(ZoneId.systemDefault()));
return new ResponseEntity<Object>(exceptionDetail, internalServerError);
}
@Override
public ResponseEntity<Object> handleTypeMismatch(
TypeMismatchException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
ExceptionDetail exceptionDetail = new ExceptionDetail(
String.format(API_UNHANDLED_EXCEPTION, ex.getMessage()),
internalServerError,
ZonedDateTime.now(ZoneId.systemDefault()));
return new ResponseEntity<Object>(exceptionDetail, internalServerError);
}
@Override
public ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException e, HttpHeaders headers,
HttpStatus status, WebRequest request) {
ExceptionDetail exceptionDetail = new ExceptionDetail(
String.format(API_UNHANDLED_EXCEPTION, e.getMessage()),
internalServerError,
ZonedDateTime.now(ZoneId.systemDefault()),
e.getBindingResult().getFieldErrors());
return new ResponseEntity<Object>(exceptionDetail, internalServerError);
}
}
当我通过 postman http://localhost:8080/api/groups/jkjk 而不是 http://localhost:8080/[=22= 发送错误的 post 请求时]
它抛出一个异常,我在调试时无法捕获初始化,无论是在 ApiGlobalExceptionHandler class 还是在 ResponseEntityExceptionHandler class:
{
"timestamp": 1604171144423,
"status": 405,
"error": "Method Not Allowed",
"message": "",
"path": "/api/groups/jkjk"
}
我能捕捉到的所有其他异常。如何捕获此异常以添加自定义处理?
您只需在其签名中添加一个新方法 with MethodNotAllowedException
。
@ExceptionHandler(value = MethodNotAllowedException.class)
public ResponseEntity<Object> handleMethodNotAllowedExceptionException(MethodNotAllowedException ex) {
return buildResponseEntity(HttpStatus.METHOD_NOT_ALLOWED, null, null, ex.getMessage(), null);
}
private ResponseEntity<Object> buildResponseEntity(HttpStatus status, HttpHeaders headers, Integer internalCode, String message, List<Object> errors) {
ResponseBase response = new ResponseBase() //A generic ResponseBase class
.success(false)
.message(message)
.resultCode(internalCode != null ? internalCode : status.value())
.errors(errors != null
? errors.stream().filter(Objects::nonNull).map(Objects::toString).collect(Collectors.toList())
: null);
return new ResponseEntity<>((Object) response, headers, status);
}
您可以根据需要自定义 buildResponseEntity
。
已更新
我重新审视了我的答案,因为它不符合您的要求。所以,它是这样的:
我发送 post 请求接受 GET
的方法。这将触发 请求方法 'POST' 不受支持,如下所示。
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.Looking up handler method for path /v1/user/profile/1
org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
org.springframework.beans.factory.support.DefaultListableBeanFactory.Returning cached instance of singleton bean 'ethGlobalExceptionHandler'
在这种情况下,不需要添加
@ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
.
事实上,如果你这样做,将会抛出以下错误(因为它已经被处理),
java.lang.IllegalStateException: Ambiguous @ExceptionHandler method mapped for [class org.springframework.web.HttpRequestMethodNotSupportedException]:....
所以,解决方案是:
@Override
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
return buildResponseEntity(HttpStatus.METHOD_NOT_ALLOWED, headers, null, ex.getMessage(), Arrays.asList(""));
}
我在这里找到了解释Custom handling for 405 error with Spring Web MVC
它说 The reason your @ExceptionHandler annotated method never catches your exception is because these ExceptionHandler annotated methods are invoked after a successful Spring controller handler mapping is found. However, your exception is raised before that.
解决方案不是从 ResponseEntityExceptionHandler class 扩展,而是从 DefaultHandlerExceptionResolver 扩展并覆盖它的 handleHttpRequestMethodNotSupported 方法。
我创建了一个 REST 应用程序并添加了一个 class 来处理异常:
@RestControllerAdvice(basePackages = "com.foxminded.university.api.controller")
public class ApiGlobalExceptionHandler extends ResponseEntityExceptionHandler {
private static final String API_UNHANDLED_EXCEPTION = "REST API reached unhandled exception: %s";
private static final HttpStatus internalServerError = HttpStatus.INTERNAL_SERVER_ERROR;
@ExceptionHandler(Exception.class)
public ResponseEntity<Object> handle(Exception e) {
ExceptionDetail exceptionDetail = new ExceptionDetail(
String.format(API_UNHANDLED_EXCEPTION, e.getMessage()),
internalServerError,
ZonedDateTime.now(ZoneId.systemDefault()));
return new ResponseEntity<Object>(exceptionDetail, internalServerError);
}
@Override
public ResponseEntity<Object> handleTypeMismatch(
TypeMismatchException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
ExceptionDetail exceptionDetail = new ExceptionDetail(
String.format(API_UNHANDLED_EXCEPTION, ex.getMessage()),
internalServerError,
ZonedDateTime.now(ZoneId.systemDefault()));
return new ResponseEntity<Object>(exceptionDetail, internalServerError);
}
@Override
public ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException e, HttpHeaders headers,
HttpStatus status, WebRequest request) {
ExceptionDetail exceptionDetail = new ExceptionDetail(
String.format(API_UNHANDLED_EXCEPTION, e.getMessage()),
internalServerError,
ZonedDateTime.now(ZoneId.systemDefault()),
e.getBindingResult().getFieldErrors());
return new ResponseEntity<Object>(exceptionDetail, internalServerError);
}
}
当我通过 postman http://localhost:8080/api/groups/jkjk 而不是 http://localhost:8080/[=22= 发送错误的 post 请求时]
它抛出一个异常,我在调试时无法捕获初始化,无论是在 ApiGlobalExceptionHandler class 还是在 ResponseEntityExceptionHandler class:
{
"timestamp": 1604171144423,
"status": 405,
"error": "Method Not Allowed",
"message": "",
"path": "/api/groups/jkjk"
}
我能捕捉到的所有其他异常。如何捕获此异常以添加自定义处理?
您只需在其签名中添加一个新方法 with MethodNotAllowedException
。
@ExceptionHandler(value = MethodNotAllowedException.class)
public ResponseEntity<Object> handleMethodNotAllowedExceptionException(MethodNotAllowedException ex) {
return buildResponseEntity(HttpStatus.METHOD_NOT_ALLOWED, null, null, ex.getMessage(), null);
}
private ResponseEntity<Object> buildResponseEntity(HttpStatus status, HttpHeaders headers, Integer internalCode, String message, List<Object> errors) {
ResponseBase response = new ResponseBase() //A generic ResponseBase class
.success(false)
.message(message)
.resultCode(internalCode != null ? internalCode : status.value())
.errors(errors != null
? errors.stream().filter(Objects::nonNull).map(Objects::toString).collect(Collectors.toList())
: null);
return new ResponseEntity<>((Object) response, headers, status);
}
您可以根据需要自定义 buildResponseEntity
。
已更新
我重新审视了我的答案,因为它不符合您的要求。所以,它是这样的:
我发送 post 请求接受 GET
的方法。这将触发 请求方法 'POST' 不受支持,如下所示。
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.Looking up handler method for path /v1/user/profile/1 org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver.Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported org.springframework.beans.factory.support.DefaultListableBeanFactory.Returning cached instance of singleton bean 'ethGlobalExceptionHandler'
在这种情况下,不需要添加
@ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
.
事实上,如果你这样做,将会抛出以下错误(因为它已经被处理),
java.lang.IllegalStateException: Ambiguous @ExceptionHandler method mapped for [class org.springframework.web.HttpRequestMethodNotSupportedException]:....
所以,解决方案是:
@Override
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
return buildResponseEntity(HttpStatus.METHOD_NOT_ALLOWED, headers, null, ex.getMessage(), Arrays.asList(""));
}
我在这里找到了解释Custom handling for 405 error with Spring Web MVC
它说 The reason your @ExceptionHandler annotated method never catches your exception is because these ExceptionHandler annotated methods are invoked after a successful Spring controller handler mapping is found. However, your exception is raised before that.
解决方案不是从 ResponseEntityExceptionHandler class 扩展,而是从 DefaultHandlerExceptionResolver 扩展并覆盖它的 handleHttpRequestMethodNotSupported 方法。