简体   繁体   English

如何使用@ExceptionHandler 捕获 HTTP 405“Method Not Allowed”异常?

[英]How to catch HTTP 405 "Method Not Allowed" exception using @ExceptionHandler?

I created a REST application and added a class to handle exceptions:我创建了一个 REST 应用程序并添加了一个类来处理异常:

@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);
    }
}

When I send the wrong post request via postman http://localhost:8080/api/groups/jkjk instead of http://localhost:8080/api/groups当我通过邮递员发送错误的帖子请求时 http://localhost:8080/api/groups/jkjk 而不是 http://localhost:8080/api/groups

It throws me an exception that I can't catch initializing when debugging, neither in the ApiGlobalExceptionHandler class nor in the ResponseEntityExceptionHandler class:它向我抛出一个异常,我在调试时无法捕获初始化,无论是在 ApiGlobalExceptionHandler 类中还是在 ResponseEntityExceptionHandler 类中:

{
    "timestamp": 1604171144423,
    "status": 405,
    "error": "Method Not Allowed",
    "message": "",
    "path": "/api/groups/jkjk"
}

All other exceptions I can catch.我可以捕获的所有其他异常。 How do I catch this exception to add custom handling?如何捕获此异常以添加自定义处理?

You just need to add a new method to with MethodNotAllowedException in its signature.您只需要在其签名中添加一个新方法 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);
}

You can customize the buildResponseEntity as you please.您可以根据需要自定义buildResponseEntity

UPDATED更新

I revisited my answer since it didn't meet your requirement.我重新审视了我的答案,因为它不符合您的要求。 So, it follows like this:所以,它是这样的:

I send post request for a method that accepts GET .我为接受GET的方法发送 post 请求。 This will fire Request method 'POST' not supported as printed below.这将触发不支持的请求方法“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' 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:不支持请求方法“POST”

In this case, there is no need to add @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class) .在这种情况下,不需要添加@ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)

In fact if you do so, the following error will be thrown (since it is already handled),事实上,如果你这样做,会抛出以下错误(因为它已经被处理了),

java.lang.IllegalStateException: Ambiguous @ExceptionHandler method mapped for [class org.springframework.web.HttpRequestMethodNotSupportedException]:....

So, the solution will be:因此,解决方案将是:

@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(""));
}

I found the explanation here Custom handling for 405 error with Spring Web MVC我在这里找到了解释自定义处理 405 错误与 Spring Web MVC

It says 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.它说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. 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.

And the solution is to extends not from ResponseEntityExceptionHandler class, but from DefaultHandlerExceptionResolver and override it handleHttpRequestMethodNotSupported method.解决方案不是从 ResponseEntityExceptionHandler 类扩展,而是从 DefaultHandlerExceptionResolver 扩展并覆盖它 handleHttpRequestMethodNotSupported 方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM