SpringBoot异常自动处理机制

2022-08-17 09:08:47

SpringBoot异常自动处理机制

ErrorMvcAutoConfiguration中注入了四个重要的类,分别是

DefaultErrorAttributes(用处共享页面中的数据)、BasicErrorController、ErrorPageCustomizer、DefaultErrorViewResolver四个类。

当发生错误时,

1、ErrorPageCustomer会将请求转发到/error地址中,

2、然后通过BasicErrorController来处理,最终的处理结果是返回一个ModelAndView(指定了转发的路径和需要渲染的数据)

这里SpringBoot是通过请求头中的信息来辨别是浏览器还是客户端

  • 如果是浏览器请求则请求BasicErrorController.errorHtml方法,响应的是一个ModelAndView。

  • 如果是客户端请求则请求BasicErrorController.error方法,响应的是JSON形式的数据

    (这里以浏览器请求为例子)

2.1、调用BasicErrorController.errorHtml(HttpServletRequest request,HttpServletResponse response)方法

@RequestMapping(produces="text/html")public ModelAndViewerrorHtml(HttpServletRequest request,
      HttpServletResponse response){
    HttpStatus status=getStatus(request);// 此处调用了getErrorAttributes来得到model,这里的getErrorAttributes就是之前注入的四个Bean之一,DefaultErrorAttributes中的方法。此方法中可以获取状态码、时间戳、错误提示等
    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?newModelAndView("error", model): modelAndView);}

2.2、errorHtml方法中调用了AbstractErrorController.resolveErrorView(HttpServletRequest request,HttpServletResponse response, HttpStatus status, Map<String, Object> model)方法。

// AbstractErrorController.resolveErrorView方法protected ModelAndViewresolveErrorView(HttpServletRequest request,
			HttpServletResponse response, HttpStatus status, Map<String, Object> model){// (注意:这里的ErrorMvcAutoConfiguration.errorViewResolvers和AbstractErrorController.errorViewResolvers是同一个,是ErrorMvcAutoConfiguration在注入Bean的时候通过构造方法传入的)for(ErrorViewResolver resolver:this.errorViewResolvers){// 遍历所有的视图解析器,找到适合的解析器// 这里调用了DefaultErrorViewResolver.resolveErrorView方法
			ModelAndView modelAndView= resolver.resolveErrorView(request, status, model);if(modelAndView!= null){return modelAndView;}}// 如果所有的视图解析器都无法解析则返回nullreturn null;}

2.3、在遍历所有视图解析器的时候调用了DefaultErrorViewResolver.resolveErrorView方法

// DefaultErrorViewResolver.resolveErrorView@Overridepublic ModelAndViewresolveErrorView(HttpServletRequest request, HttpStatus status,
			Map<String, Object> model){// 首先传入具体的状态码来解析,如404
		ModelAndView modelAndView=resolve(String.valueOf(status), model);// 如果视图为空,并且错误代码为4xx或者5xx则传入状态码和model进行解析if(modelAndView== null&& SERIES_VIEWS.containsKey(status.series())){
			modelAndView=resolve(SERIES_VIEWS.get(status.series()), model);}return modelAndView;}// DefaultErrorViewResolver.resolve方法private ModelAndViewresolve(String viewName, Map<String, Object> model){// 根据传入的状态码去 "error/" 下寻找是否有对应页面
		String errorViewName="error/"+ viewName;// 模板引擎可以解析这个页面地址就用模板引擎解析
		TemplateAvailabilityProvider provider=this.templateAvailabilityProviders.getProvider(errorViewName,this.applicationContext);if(provider!= null){// 模板引擎可用的情况下返回到errorViewName指定的视图地址returnnewModelAndView(errorViewName, model);}// 模板引擎不可用则在静态资源文件夹下寻找errorViewName对应的页面returnresolveResource(errorViewName, model);}// 去静态资源文件夹下找对应的页面,找不到则返回nullprivate ModelAndViewresolveResource(String viewName, Map<String, Object> model){for(String location:this.resourceProperties.getStaticLocations()){try{
				Resource resource=this.applicationContext.getResource(location);
				resource= resource.createRelative(viewName+".html");if(resource.exists()){returnnewModelAndView(newHtmlResourceView(resource), model);}}catch(Exception ex){}}return null;}

2.4、注意看2.1步骤中的代码,如果最后解析返回一个ModelAndView则会直接渲染后响应给请求,如果返回的是null,则会生成一个名为 “error” 的 ModelAndView ,也就是我们熟知的默认错误页面。

@Configuration@ConditionalOnProperty(prefix="server.error.whitelabel", name="enabled", matchIfMissing=true)@Conditional(ErrorTemplateMissingCondition.class)protectedstaticclassWhitelabelErrorViewConfiguration{privatefinal SpelView defaultErrorView=newSpelView("<html><body><h1>Whitelabel Error Page</h1>"+"<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>"+"<div id='created'>${timestamp}</div>"+"<div>There was an unexpected error (type=${error}, status=${status}).</div>"+"<div>${message}</div></body></html>");@Bean(name="error")@ConditionalOnMissingBean(name="error")public ViewdefaultErrorView(){returnthis.defaultErrorView;}// If the user adds @EnableWebMvc then the bean name view resolver from// WebMvcAutoConfiguration disappears, so add it back in to avoid disappointment.@Bean@ConditionalOnMissingBean(BeanNameViewResolver.class)public BeanNameViewResolverbeanNameViewResolver(){
			BeanNameViewResolver resolver=newBeanNameViewResolver();
			resolver.setOrder(Ordered.LOWEST_PRECEDENCE-10);return resolver;}}

如何定制错误的响应信息

定制错误页面

在上面也2.3中有分析到DefaultErrorViewResolver中视图解析器是如何解析的,**有模板引擎的情况下直接将对应错误状态码的html页面放入error文件夹下即可。**也可以使用 “4xx.html” 或者"5xx.html" 来处理一种类型的错误。没有模板引擎则直接去静态资源文件夹下找,如果静态资源也找不到则返回SpringBoot的默认错误页面

  • 作者:fx_____
  • 原文链接:https://blog.csdn.net/weixin_40776321/article/details/95479970
    更新时间:2022-08-17 09:08:47