Spring Boot - обработка исключения NoHandlerFoundException

Прочтите Справочное руководство Spring по обработке исключения NoHandlerFoundException и обнаружите, что Spring по умолчанию устанавливает throwExceptionIfNoHandlerFound в false.

Зная это, я подумал, что было бы неплохо установить этот параметр на true.

Я использую Spring Boot.

Сделал так:

MyConfig.java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;

@SpringBootApplication
public class MyConfig {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(MyConfig.class, args);
        context.getBean(DispatcherServlet.class).setThrowExceptionIfNoHandlerFound(true);

        // ...
    }
}

Хорошо, теперь throwExceptionIfNoHandlerFound равен true. Однако это не сработало, как ожидалось. DispatcherServlet продолжал не бросать NoHandlerFoundException. Таким образом, я не смог справиться с этим.

CustomExceptionHandler.java(это не сработало)

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity <Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        // do my own handle ...

        // then, return ...
    }

}

После небольшого поиска обнаружил, что добавление @EnableWebMvc должно работать. Затем я добавил эту аннотацию к своему CustomExceptionHandler.

CustomExceptionHandler.java(это сработало)

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@EnableWebMvc
@ControllerAdvice
public class CustomExceptionHandler extends ResponseEntityExceptionHandler {

    @Override
    protected ResponseEntity <Object> handleNoHandlerFoundException(NoHandlerFoundException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        // do my own handle ...

        // then, return ...
    }

}

Таким образом, ручка работает. Однако я использую Spring Boot. Документы Spring Boot предполагают, что если я вставлю @EnableWebMvc, я потеряю некоторые функции автоконфигурации Spring Boot MVC, поскольку я возьму на себя полный контроль над Spring MVC. (Глянь сюда).

"If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc."

Могу ли я потерять автоконфигурацию Spring MVC? Я имею в виду, что в моем случае @EnableWebMvc не принадлежит к классу @Configuration.

Мой вопрос основан на том факте, что я не уверен, как работает приведенный выше код, и хочу знать, есть ли другой способ сделать это без потери автоконфигурации Spring MVC. Может кто-нибудь объяснить?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
4
0
9 372
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Автоконфигурация Spring Boot автоматически добавит ResourceHttpRequestHandler для работы со статическим ресурсом. По умолчанию этот обработчик сопоставляется с /** и является последним элементом в цепочке обработчиков.

Это означает, что DispatcherServlet не выдаст NoHandlerFoundException, потому что он нашел обработчик ресурсов. Обработчик ресурсов обрабатывает запрос и вызывает response.sendError(HttpServletResponse.SC_NOT_FOUND), чтобы вернуть 404.

Если вам не нужно такое поведение, вы можете добавить к своему application.properties следующее:

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

Он настроит сервлет диспетчера для выдачи исключения. а также также сообщит Spring Boot не регистрировать обработчик ресурсов.

Прежде чем вы зайдете слишком далеко по этому пути, вы можете посмотреть эта секция справочной документации, чтобы увидеть, не лучше ли обрабатывать эти ошибки другим способом. Из вашего вопроса не совсем понятно, что вы на самом деле пытаетесь сделать в своем обработчике ошибок, но если он просто имеет дело с 404, то, вероятно, есть лучший способ.

Спасибо, Фил. В Spring Boot 2.3 включение этих свойств не имеет никакого эффекта. Например, после реализации ResponseEntityExceptionHandler#handleHttpRequestMethodNotSup‌​portedDispatcherServlet отправляет запрос с неподдерживаемым методом HTTP в /error, а не этому обработчику. Проблема в том, что ErrorController является контейнером для всего контейнера, поэтому, если у меня есть несколько контроллеров, каждый из которых требует отправки разных сообщений JSON при ошибках (специфичных для этих контроллеров), тогда я привязан и должен прибегнуть к проверке перенаправленного URI. Есть ли причина, по которой Spring ведет себя так?

NuCradle 18.09.2020 16:27

Другие вопросы по теме