Spring Boot - Обработка stati c ресурсов, которые не найдены (404), и возможность определить причину исключения - PullRequest
0 голосов
/ 16 июня 2020

В моем приложении Spring Boot (2.3.1.RELEASE) я обслуживаю stati c ресурсы, используя:

@Configuration
public class StaticResourceConfiguration implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/favicon.ico").addResourceLocations("classpath:/static/favicon.ico");
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}

Это отлично работает. Но я не могу правильно управлять ресурсом stati c , который не найден . Я хочу, чтобы в этом случае вызывался специальный обработчик.

Моя текущая стратегия в моем приложении - управлять всеми исключениями в одном методе. Вот что я сейчас делаю:

@ControllerAdvice
@RestController
public class AppErrorController implements ErrorController {

    @Autowired
    private ErrorAttributes errorAttributes;

    @Override
    public String getErrorPath() {
        return "/error";
    }

    @ExceptionHandler(Exception.class)
    @RequestMapping("/error")
    public ErrorResponse handleError(WebRequest webRequest, HttpServletRequest request, HttpServletResponse response) {

        // Get access to the actual Exception
        Throwable ex = this.errorAttributes.getError(webRequest);

        // Check if it is a 404 exception
        if (ex != null && instanceof NoHandlerFoundException) {
            // Manage the error as a 404!
            // ...
        } else {
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
            ErrorResponse errorResponse = new ErrorResponse("generalError", "An error occured");
            return errorResponse;
        }
    }
}

Это работает хорошо, за исключением одного случая: когда ресурс stati c не найден! Затем Spring вызывает метод handleError из-за @RequestMapping("/error"), но в этом случае исключение, возвращаемое this.errorAttributes.getError(webRequest), будет null! Поэтому я не могу знать, что это на самом деле 404 , и поэтому мой код возвращает общую ошибку 500.

Как я могу обработать запрос к несуществующему stati c ресурс и иметь возможность определить причину, чтобы я мог вернуть 404 вместо 500?

EDIT :

Я использую эти конфигурации в application.properties:

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

Ответы [ 2 ]

0 голосов
/ 17 июня 2020

На данный момент я нашел единственный способ заставить его работать - это надеяться, что только stati c ресурсы, которые не найдены, заставят Spring вызвать мой /error маршрут, и ничего больше ...

Кроме того, я возвращаю статус HTTP с webRequest.getAttribute(RequestDispatcher.ERROR_STATUS_CODE, RequestAttributes.SCOPE_REQUEST). Да, это уродливо, и я открыт для любого более чистого решения !!

Итак, теперь у меня есть что-то вроде:

@ControllerAdvice
@RestController
public class AppErrorController implements ErrorController {

    @Autowired
    private ErrorAttributes errorAttributes;

    @Override
    public String getErrorPath() {
        return "/error";
    }

    // Manage REST exceptions
    @ExceptionHandler(Exception.class)
    public ErrorResponse handleError(WebRequest webRequest, HttpServletRequest request, HttpServletResponse response) {

        // Ok, not null!
        Throwable ex = this.errorAttributes.getError(webRequest);

        response.setStatus(XXXXXX);
        return new ErrorResponse("My REST error");
    }

    // Manage other exceptions (like static resources that
    // do not exist - 404)
    @RequestMapping(AppConstants.ROUTE_ERROR)
    public String errorRoute(WebRequest webRequest, HttpServletRequest request, HttpServletResponse response) {

        int status = HttpStatus.INTERNAL_SERVER_ERROR.value();
        Object statusObj = webRequest.getAttribute(RequestDispatcher.ERROR_STATUS_CODE, RequestAttributes.SCOPE_REQUEST);
        if (statusObj != null) {
            status = ((Integer)statusObj).intValue();
        }

        response.setStatus(status);
        return HttpStatus.NOT_FOUND.value() + "";
    }

}
0 голосов
/ 17 июня 2020

Настраивает обработчик запросов для обслуживания ресурсов c stati, перенаправляя запрос сервлету "по умолчанию" контейнера сервлета. DefaultServletHandlerConfigurer

@Configuration
public class StaticResourceConfiguration implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/favicon.ico").addResourceLocations("/static/favicon.ico");
        registry.addResourceHandler("/static/**").addResourceLocations("/static/");
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("forward:/resources/static/index.html");
        registry.addViewController("/error").setViewName("forward:/resources/error/404.html");
        registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
   }
}

Или с помощью ControllerAdvice.

@Slf4j
@Order(ORDER)
@RestControllerAdvice(annotations = RestController.class)
public class GlobalRestControllerAdvice {

    public static final int ORDER = 0;

    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NotFoundException.class)
    public Map<String, String> handle(NotFoundException e) {
        log.error(e.getMessage(), e);
        Map<String, String> errorAttributes = new HashMap<>();
        errorAttributes.put("code", "NOT_FOUND");
        errorAttributes.put("message", e.getMessage());
        return errorAttributes;
    }
}

@Slf4j
@Order(GlobalRestControllerAdvice.ORDER + 1)
@ControllerAdvice
public class GlobalHtmlControllerAdvice {

    @ResponseStatus(HttpStatus.NOT_FOUND)
    @ExceptionHandler(NotFoundException.class)
    public String handle(NotFoundException e, Model model, HttpServletRequest request) {
        log.error(e.getMessage(), e);
        model.addAttribute("timestamp", LocalDateTime.now());
        model.addAttribute("error", "NOT_FOUND");
        model.addAttribute("path", request.getRequestURI());
        model.addAttribute("message", e.getMessage());
        return "/error/404";
    }
}

и ErrorAttributes getError () - Возвращает: исключение, вызвавшее ошибку, или null.

...