背景
在使用SpringBoot的过程中,你肯定遇到过404错误。比如下面的代码:
@RestController @RequestMapping(value = "/hello") public class HelloWorldController { @RequestMapping("/test") public Object getObject1(HttpServletRequest request){ Response response = new Response(); respo<i>本文来源gaodai$ma#com搞$代*码*网</i>nse.success("请求成功..."); response.setResponseTime(); return response; } }
当我们使用错误的请求地址(POST http://127.0.0.1:8888/hello/test1?id=98)进行请求时,会报下面的错误:
{ "timestamp": "2020-11-19T08:30:48.844+0000", "status": 404, "error": "Not Found", "message": "No message available", "path": "/hello/test1" }
虽然上面的返回很清楚,但是我们的接口需要返回统一的格式,比如:
{ "rtnCode":"9999", "rtnMsg":"404 /hello/test1 Not Found" }
这时候你可能会想有Spring的统一异常处理,在Controller类上加@RestControllerAdvice注解。但是这种做法并不能统一处理404错误。
404错误产生的原因
产生404的原因是我们调了一个不存在的接口,但是为什么会返回下面的json报错呢?我们先从Spring的源代码分析下。
{ "timestamp": "2020-11-19T08:30:48.844+0000", "status": 404, "error": "Not Found", "message": "No message available", "path": "/hello/test1" }
为了代码简单起见,这边直接从DispatcherServlet的doDispatch方法开始分析。(如果不知道为什么要从这边开始,你还要熟悉下SpringMVC的源代码)。
... 省略部分代码.... // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); ... 省略部分代码
Spring MVC会根据请求URL的不同,配置的RequestMapping的不同,为请求匹配不同的HandlerAdapter。
对于上面的请求地址:http://127.0.0.1:8888/hello/test1?id=98匹配到的HandlerAdapter是HttpRequestHandlerAdapter。
我们直接进入到HttpRequestHandlerAdapter中看下这个类的handle方法。
@Override @Nullable public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((HttpRequestHandler) handler).handleRequest(request, response); return null; }
这个方法没什么内容,直接是调用了HttpRequestHandler类的handleRequest(request, response)方法。所以直接进入这个方法看下吧。
@Override public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // For very general mappings (e.g. "/") we need to check 404 first Resource resource = getResource(request); if (resource == null) { logger.trace("No matching resource found - returning 404"); // 这个方法很简单,就是设置404响应码,然后将Response的errorState状态从0设置成1 response.sendError(HttpServletResponse.SC_NOT_FOUND); // 直接返回 return; } ... 省略部分方法 }
这个方法很简单,就是设置404响应码,将Response的errorState状态从0设置成1,然后就返回响应了。整个过程并没有发生任何异常,所以不能触发Spring的全局异常处理机制。