Spring Boot - 掌控404 Not Found
Spring Boot - 掌控404 Not Found
我正在尝试找出一种最简单的方法来控制基本的Spring Boot RESTful服务的404 Not Found处理程序,例如Spring提供的示例:https://spring.io/guides/gs/rest-service/。而不是返回默认的Json输出:{
"timestamp":1432047177086,
"status":404,
"error":"Not Found",
"exception":"org.springframework.web.servlet.NoHandlerFoundException",
"message":"No handler found for GET /aaa, ..."
}
。我想提供自己的Json输出。通过控制DispatcherServlet
并使用DispatcherServlet#setThrowExceptionIfNoHandlerFound(true)
,我能够使其在404的情况下抛出异常,但是我无法通过@ExceptionHandler
来处理该异常,就像处理MissingServletRequestParameterException
一样。有什么想法吗?或者有没有比抛出和处理NoHandlerFoundException更好的方法?
Spring Boot是一个非常方便的框架,但是它在处理404 Not Found错误时并没有明确的处理方式,而是使用了WebMvc的错误响应。如果你希望Spring Boot能够处理这个异常,那么你需要对Spring Boot进行一些修改。对于404错误,异常类是NoHandlerFoundException;如果你想在你的类中处理这个异常,你必须在你的Application类中添加以下注解,并在DispatcherServlet中设置setThrowExceptionIfNoHandlerFound(true)。请参考以下代码:
public class Application { private DispatcherServlet servlet; public static void main(String[] args) throws FileNotFoundException, IOException { SpringApplication.run(Application.class, args); } public CommandLineRunner getCommandLineRunner(ApplicationContext context) { servlet.setThrowExceptionIfNoHandlerFound(true); return args -> {}; } }
在这之后,你就可以在你的类中处理NoHandlerException了。
public class AppException { @ExceptionHandler(value={NoHandlerFoundException.class}) @ResponseStatus(code=HttpStatus.BAD_REQUEST) public ApiError badRequest(Exception e, HttpServletRequest request, HttpServletResponse response) { e.printStackTrace(); return new ApiError(400, HttpStatus.BAD_REQUEST.getReasonPhrase()); } }
我创建了一个ApiError类来返回自定义的错误响应。
public class ApiError { private int code; private String message; public ApiError(int code, String message) { this.code = code; this.message = message; } public ApiError() { } //getter & setter methods... }
添加@EnableWebMvc注解将完全关闭Spring Boot对Spring MVC的自动配置,因此所有spring.mvc.*配置属性将被忽略。详细信息请参考参考文档[docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc-auto-configuration](docs.spring.io/spring-boot/docs/current/reference/html/…)。
根据Spring文档附录A,有一个名为"spring.mvc.throw-exception-if-no-handler-found"的布尔属性,可以用来启用抛出"NoHandlerFoundException"异常。然后你可以像处理其他异常一样创建异常处理程序。
class MyExceptionHandler { private static final Logger log = LoggerFactory.getLogger(MyExceptionHandler.class); @ResponseStatus(HttpStatus.NOT_FOUND) @ExceptionHandler(NoHandlerFoundException.class) public String handleNoHandlerFoundException(NoHandlerFoundException ex) { log.error("404 situation detected.",ex); return "Specified path not found on this server"; } }
不能使用没有控制器的`@ControllerAdvice`本身,因为它只与其控制器绑定。
在Spring Boot中,当出现404 Not Found错误时,实际上是由容器抛出的NoHandlerFoundException
异常,而不是由应用程序内部抛出的。因此,容器无法了解到你的应用程序中的@RequestMapping
注解,因为这是Spring的特性,而不是容器的特性。
解决这个问题的方法是使用HandlerExceptionResolver
。我之前也遇到了和你一样的问题,你可以查看我在这个链接中的解决方案:How to intercept "global" 404s on embedded Tomcats in spring-boot