一、默认效果
Spring Boot在默认情况下,对浏览器访问和其他客户端访问的处理机制是不同的。
1、浏览器访问
浏览器访问返回错误页面,错误页面中带有错误状态码,错误类型,提示信息等。
浏览器发送的请求头:
2、其他客户端访问
其他客户端访问,默认响应一个JSON数据,JSON数据中带有错误状态码,错误类型,提示信息等。
其他客户端发送的请求头
二、原理说明
Spring Boot的错误处理的自动配置参照ErrorMvcAutoConfiguration,该自动配置类主要向容器中添加了以下四个组件。
一、DefaultErrorAttributes
/*** 帮我们在页面共享信息,设置页面上的错误信息**/@Overridepublic Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes,boolean includeStackTrace) {Map<String, Object> errorAttributes = new LinkedHashMap<String, Object>();errorAttributes.put("timestamp", new Date());addStatus(errorAttributes, requestAttributes);addErrorDetails(errorAttributes, requestAttributes, includeStackTrace);addPath(errorAttributes, requestAttributes);return errorAttributes;}
二、BasicErrorController
/*** 处理默认的/error请求**/@Controller@RequestMapping("${server.error.path:${error.path:/error}}")public class BasicErrorController extends AbstractErrorController {// 处理浏览发送的请求,产生html类型的数据@RequestMapping(produces = "text/html")public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {HttpStatus status = getStatus(request);Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML)));response.setStatus(status.value());// 视图解析器,决定要去哪个错误页面,包含页面地址和页面内容ModelAndView modelAndView = resolveErrorView(request, response, status, model);return (modelAndView == null ? new ModelAndView("error", model) : modelAndView);}// 处理其他客户端发送的请求,产生json数据@RequestMapping@ResponseBodypublic ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {Map<String, Object> body = getErrorAttributes(request,isIncludeStackTrace(request, MediaType.ALL));HttpStatus status = getStatus(request);return new ResponseEntity<Map<String, Object>>(body, status);}
三、ErrorPageCustomizer
// 系统出现错误以后来到error请求进行处理(web.xml注册的错误页面规则)@Value("${error.path:/error}")private String path = "/error";
四、DefaultErrorViewResolver
@Overridepublic ModelAndView resolveErrorView(HttpServletRequest request,HttpStatus status, Map<String, Object> model) {ModelAndView modelAndView = resolve(String.valueOf(status), model);if (modelAndView == null && SERIES_VIEWS.containsKey(status.series())) {modelAndView = resolve(SERIES_VIEWS.get(status.series()), model);}return modelAndView;}private ModelAndView resolve(String viewName, Map<String, Object> model) {//去error目录下找和状态码一致的错误页面 例如:404.ftlString errorViewName = "error/" + viewName;// 模板引擎可以解析这个页面地址就用模板引擎解析TemplateAvailabilityProvider provider = this.templateAvailabilityProviders.getProvider(errorViewName, this.applicationContext);if (provider != null) {// 模板引擎可用的情况下返回到errorViewName指定的视图地址return new ModelAndView(errorViewName, model);}// 模板引擎不可用,就在静态资源文件夹下找errorViewName对应的页面return resolveResource(errorViewName, model);}
一旦系统出现错误(例如:4xx/5xx),
ErrorPageCustomizer就会生效,处理错误信息,然后来到/error请求,被BasicErrorController处理。
/*** 具体响应页面由DefaultErrorViewResolver解析得到**/protected ModelAndView resolveErrorView(HttpServletRequest request,HttpServletResponse response, HttpStatus status, Map<String, Object> model) {// 所有的ErrorViewResolver得到ModelAndViewfor (ErrorViewResolver resolver : this.errorViewResolvers) {ModelAndView modelAndView = resolver.resolveErrorView(request, status, model);if (modelAndView != null) {return modelAndView;}}return null;}
Spring Boot错误页面默认放在资源路径的
/error目录下,页面名称即错误代码(例如:404.ftl),你可以用“x”做错误页面模糊匹配(例如:4xx.ftl 匹配所有4开头的错误码)。同时存在时,精确优先。
