SpringBoot

您所在的位置:网站首页 页面返回400是什么错误 SpringBoot

SpringBoot

2024-07-01 11:07| 来源: 网络整理| 查看: 265

优质博文:IT-BLOG-CN

一、SpringBoot 默认的错误处理机制

【1】浏览器返回的默认错误页面如下:

☞ 浏览器发送请求的请求头信息如下: text/html会在后面的源码分析中说到。

【2】如果是其他客户端,默认则响应错误的 JSON字符串,如下所示:

☞ 其他客户端发送请求的请求头信息如下: */* 源码中解释。

二、原理分析

参照ErrorMvcAutoConfiguration类: 错误处理的自动配置类,以下4项为此类的重要信息。

【1】ErrorMvcAutoConfiguration.ErrorPageCustomizer: 当系统出现 4xx或者 5xx之类的错误时,ErrorPageCustomizer就会生效(定制错误的响应规则),根据如下源码可知,将会来到/error请求。

@Bean public ErrorMvcAutoConfiguration.ErrorPageCustomizer errorPageCustomizer() { return new ErrorMvcAutoConfiguration.ErrorPageCustomizer(this.serverProperties); } //进入ErrorPageCustomizer方法,发现registerErrorPages方法:注册一个错误也 private static class ErrorPageCustomizer implements ErrorPageRegistrar, Ordered { private final ServerProperties properties; protected ErrorPageCustomizer(ServerProperties properties) { this.properties = properties; } public void registerErrorPages(ErrorPageRegistry errorPageRegistry) { ErrorPage errorPage = new ErrorPage(this.properties.getServletPrefix() + this.properties.getError().getPath()); errorPageRegistry.addErrorPages(new ErrorPage[]{errorPage}); } } //进入this.properties.getError().getPath()方法,获取如下信息,得到/error请求。 @Value("${error.path:/error}") private String path = "/error";//系统出现错误以后来到error请求进行处理;(web.xml注册的错误页面规则)

【2】BasicErrorController 处理 /error错误请求: 注意:text/html和*/*就是在此处生效。

@Bean @ConditionalOnMissingBean( value = {ErrorController.class}, search = SearchStrategy.CURRENT ) public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) { return new BasicErrorController(errorAttributes, this.serverProperties.getError(), this.errorViewResolvers); } //进入BasicErrorController对象,获取如下信息 @Controller @RequestMapping({"${server.error.path:${error.path:/error}}"}) public class BasicErrorController extends AbstractErrorController { private final ErrorProperties errorProperties; public BasicErrorController(ErrorAttributes errorAttributes, ErrorProperties errorProperties) { this(errorAttributes, errorProperties, Collections.emptyList()); } @RequestMapping( produces = {"text/html"}//产生html类型的数据;浏览器发送的请求来到这个方法处理 ) public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { HttpStatus status = this.getStatus(request); Map model = Collections.unmodifiableMap(this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.TEXT_HTML))); response.setStatus(status.value()); //去哪个页面作为错误页面;包含页面地址和页面内容 ModelAndView modelAndView = this.resolveErrorView(request, response, status, model); return modelAndView != null?modelAndView:new ModelAndView("error", model); } @RequestMapping @ResponseBody//产生json数据,其他客户端来到这个方法处理; public ResponseEntity error(HttpServletRequest request) { Map body = this.getErrorAttributes(request, this.isIncludeStackTrace(request, MediaType.ALL)); HttpStatus status = this.getStatus(request); return new ResponseEntity(body, status); } }

☞ 如上代码中提到的错误页面解析代码,进入此方法: this.resolveErrorView(request, response, status, model);

protected ModelAndView resolveErrorView(HttpServletRequest request, HttpServletResponse response, HttpStatus status, Map model) { Iterator var5 = this.errorViewResolvers.iterator(); ModelAndView modelAndView; do { //从所有的ErrorViewResolver得到ModelAndView if(!var5.hasNext()) { return null; } ErrorViewResolver resolver = (ErrorViewResolver)var5.next(); modelAndView = resolver.resolveErrorView(request, status, model); } while(modelAndView == null); return modelAndView; }

【3】最终的响应页面是由DefaultErrorViewResolver解析得到的: 最重要的信息是,SpringBoot默认模板引擎的/error目录下获取 ‘status’.xml 错误页面,也可以通过4xx.xml来统配 404.xml和 400.xml等等,但是优先获取精准的页面。如果模板引擎中不存在,则会从静态页面中获取错误页面。否则返回系统默认错误页面。

@Bean @ConditionalOnBean({DispatcherServlet.class}) @ConditionalOnMissingBean public DefaultErrorViewResolver conventionErrorViewResolver() { return new DefaultErrorViewResolver(this.applicationContext, this.resourceProperties); } //进入DefaultErrorViewResolver类中 public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map model) { ModelAndView modelAndView = this.resolve(String.valueOf(status), model); if(modelAndView == null && SERIES_VIEWS.containsKey(status.series())) { //调用时viewname = status ***重要 modelAndView = this.resolve((String)SERIES_VIEWS.get(status.series()), model); } return modelAndView; } private ModelAndView resolve(String viewName, Map model) { //默认SpringBoot可以去找到一个页面? error/404 String errorViewName = "error/" + viewName; //模板引擎可以解析这个页面地址就用模板引擎解析 TemplateAvailabilityProvider provider = this.templateAvailabilityProviders. getProvider(errorViewName, this.applicationContext); //模板引擎可用的情况下返回到errorViewName指定的视图地址, //当模板引擎不可用,就在静态资源文件夹下找errorViewName对应的页面 error/404.html return provider != null?new ModelAndView(errorViewName, model):this.resolveResource(errorViewName, model); }

【4】DefaultErrorAttributes: 在页面添加错误信息,供我们使用。

@Bean @ConditionalOnMissingBean( value = {ErrorAttributes.class}, search = SearchStrategy.CURRENT ) public DefaultErrorAttributes errorAttributes() { return new DefaultErrorAttributes(); } //进入DefaultErrorAttributes类中,发现此方法给视图中添加了status状态等信息,供我们使用。 public Map getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) { Map errorAttributes = new LinkedHashMap(); errorAttributes.put("timestamp", new Date()); this.addStatus(errorAttributes, requestAttributes); this.addErrorDetails(errorAttributes, requestAttributes, includeStackTrace); this.addPath(errorAttributes, requestAttributes); return errorAttributes; } 三、定制错误 JSON数据

【1】自定义异常处理类,返回定制的 JSON数据。通过上述的分析,我们得知:  ①、可以完全编写一个ErrorController的实现类,或者继承AbstractErrorController的子类,放入容器中。  ②、也可以自定义异常处理类,返回 JSON数据。  ③、页面上的数据或 JSON返回的数据都是可以通过errorAttributes.getErrorAttributes得到的。我们可以自定义属于自己的ErrorAttributes。

//首先我们可以通过自定义异常处理,来确定返回的数据,但这个不够灵活,我们可以与③结合使用 /** * @RequestMapping启动应用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,都会作用在 被 @RequestMapping * 注解的方法上。 */ @ControllerAdvice public class MyExceptionHandler { @ResponseBody @ExceptionHandler(UserNotExistException.class) public Map handlerException(Exception e, HttpServletRequest request){ Map map = new HashMap(); request.setAttribute("javax.servlet.error.status_code","500"); map.put("code","user.notexist"); map.put("message",e.getMessage()); return map; } } //③自定义ErrorAttributes,一定要加入容器 @Component public class MyErrorAttributes extends DefaultErrorAttributes{ @Override public Map getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) { //获取默认的配置,在此基础上添加自己的需求 Map map = super.getErrorAttributes(requestAttributes, includeStackTrace); //自定义自己需要的属性 map.put("company","yintong"); //获取我们在异常处理类中添加的信息, /*注意:当我们需要结合使用的时候异常处理必须return "forward:/error";将请求转发出去,不能直接返回map对象, 同时要去掉@responseBody注解,否则ErrorAttributes不生效*/ map.put("ext",requestAttributes.getAttribute("ext",requestAttributes.SCOPE_REQUEST)); return map; } }

【2】效果展示:



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3