通常我们在Spring Boot中设置的统一异常处理只能处理Controller抛出的异常。有些请求还没到Controller就出异常了,而这些异常不能被统一异常捕获,例如Servlet容器的某些异常。


通常我们在Spring Boot中设置的统一异常处理只能处理Controller抛出的异常。有些请求还没到Controller就出异常了,而这些异常不能被统一异常捕获,例如Servlet容器的某些异常。今天我在项目开发中就遇到了一个,这让我很不爽,因为它返回的错误信息格式不能统一处理,我决定找个方案解决这个问题。

ErrorPageFilter


Whitelabel Error Page

这类图相信大家没少见,Spring Boot 只要出错,体现在页面上的就是这个。如果你用Postman之类的测试出了异常则是:

{ "timestamp": "2021-04-29T22:45:33.231+0000", "status": 500, "message": "Internal Server Error", "path": "foo/bar"
}

这个是怎么实现的呢?Spring Boot在启动时会注册一个ErrorPageFilter,当Servlet发生异常时,该过滤器就会拦截处理,将异常根据不同的策略进行处理:当异常已经在处理的话直接处理,否则转发给对应的错误页面。有兴趣的可以去看下源码,逻辑不复杂,这里就不贴了。

另外当一个 Servlet 抛出一个异常时,处理异常的Servlet可以从HttpServletRequest里面得到几个属性,如下:

异常属性

我们可以从上面的几个属性中获取异常的详细信息。

默认错误页面

通常Spring Boot出现异常默认会跳转到/error进行处理,而/error的相关逻辑则是由BasicErrorController实现的。

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController extends AbstractErrorController { //返回错误页面 @RequestMapping(produces = MediaType.TEXT_HTML_VALUE) public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { HttpStatus status = getStatus(request); Map model = Collections .unmodifiableMap(getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.TEXT_HTML))); response.setStatus(status.value()); ModelAndView modelAndView = resolveErrorView(request, response, status, model); return (modelAndView != null) ? modelAndView : new ModelAndView("error", model); } // 返回json @RequestMapping public ResponseEntity> error(HttpServletRequest request) { HttpStatus status = getStatus(request); if (status == HttpStatus.NO_CONTENT) { return new ResponseEntity<>(status); } Map body = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL)); return new ResponseEntity<>(body, status); }
// 其它省略
}

而对应的配置:

@Bean
@ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes, ObjectProvider errorViewResolvers) { return new BasicErrorController(errorAttributes, this.serverProperties.getError(), errorViewResolvers.orderedStream().collect(Collectors.toList()));
}

所以我们只需要重新实现一个ErrorController并注入Spring IoC就可以替代默认的处理机制。而且我们可以很清晰的发现这个BasicErrorController不但是ErrorController的实现而且是一个控制器,如果我们让控制器的方法抛异常,肯定可以被自定义的统一异常处理。所以我对BasicErrorController进行了改造:

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class ExceptionController extends AbstractErrorController { public ExceptionController(ErrorAttributes errorAttributes) { super(errorAttributes); } @Override @Deprecated public String getErrorPath() { return null; } @RequestMapping(produces = MediaType.TEXT_HTML_VALUE) public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) { throw new RuntimeException(getErrorMessage(request)); } @RequestMapping public ResponseEntity> error(HttpServletRequest request) { throw new RuntimeException(getErrorMessage(request)); } private String getErrorMessage(HttpServletRequest request) { Object code = request.getAttribute("javax.servlet.error.status_code"); Object exceptionType = request.getAttribute("javax.servlet.error.exception_type"); Object message = request.getAttribute("javax.servlet.error.message"); Object path = request.getAttribute("javax.servlet.error.request_uri"); Object exception = request.getAttribute("javax.servlet.error.exception"); return String.format("code: %s,exceptionType: %s,message: %s,path: %s,exception: %s", code, exceptionType, message, path, exception); }
}

直接抛异常,简单省力!凡是这里捕捉的到的异常大部分还没有经过Controller,我们通过ExceptionController中继也让这些异常被统一处理,保证整个应用的异常处理对外保持一个统一的门面。

Spring Boot统一异常处理的拦截指南相关推荐

  1. Spring Boot统一异常处理实践

    Spring Boot统一异常处理实践 参考文章: (1)Spring Boot统一异常处理实践 (2)https://www.cnblogs.com/fundebug/p/springboot-ex ...

  2. Spring Boot 统一功能处理(用户登录权限效验-拦截器、异常处理、数据格式返回)

    文章目录 1. 统一用户登录权限效验 1.1 最初用户登录权限效验 1.2 Spring AOP 统一用户登录验证 1.3 Spring 拦截器 1.4 练习:登录拦截器 1.5 拦截器实现原理 1. ...

  3. Spring Boot默认异常处理BasicErrorController源码解读

    小伙伴们是不是刚接触Spring Boot做网页开发的时候,如果代码发生异常,会返回一个错误信息页面,如下图 那么这个页面是怎么返回的呢,这里就要接触到一个Spring Boot类BasicError ...

  4. Spring Boot 统一功能处理

    Spring Boot 统一功能处理 一.使用 Spring 拦截器来实现登录验证 引入 代码实现 步骤1 自定义拦截器 步骤2 添加拦截器并设置拦截规则 拦截规则 步骤3 创建前后端交互,用于测试 ...

  5. Spring MVC统一异常处理

    Spring MVC统一异常处理 一.为什么需要统一异常处理? 1.1 try catch带来的问题 平时项目中处理Controller层异常很多时候都会使用try catch去捕获异常(包括Cont ...

  6. 编程小白入门分享三:Spring AOP统一异常处理

    编程小白入门分享三:Spring AOP统一异常处理 参考文章: (1)编程小白入门分享三:Spring AOP统一异常处理 (2)https://www.cnblogs.com/lxk12345/p ...

  7. spring mvc统一异常处理(@ControllerAdvice + @ExceptionHandler)

    spring mvc统一异常处理(@ControllerAdvice + @ExceptionHandler) 参考文章: (1)spring mvc统一异常处理(@ControllerAdvice ...

  8. spring boot 全局异常处理的实现(@ExceptionHandler),以及@InitBinder、@ModelAttribute的作用

    spring boot 全局异常处理的实现(@ExceptionHandler),以及@InitBinder.@ModelAttribute的作用 参考文章: (1)spring boot 全局异常处 ...

  9. Spring Boot 全局异常处理(400/404/500),顺便解决过滤器中异常未捕获到的问题,让RestApi 任何时候都能获取统一的格式代码

    出发点是为了在系统抛出异常的时候,前端仍然可以获取到统一的报文格式,所以后端所有的异常都得捕获,并处理 Spring boot 在处理异常的时候,500/404默认都会转发到/error,而这个异常的 ...

最新文章

  1. rfc6455 WebSockets
  2. JS 获取 鼠标 坐标
  3. MySQL命令窗口出现中文乱码的解决方法
  4. 标准模板库 STL—— set 列传
  5. 回斯坦福之后研究成果曝光,李飞飞团队用机器学习教机械臂做动作
  6. 4.企业安全建设指南(金融行业安全架构与技术实践) --- 内控合规管理
  7. 线程知识点——Event事件
  8. C语言贪吃蛇 新手入门(超详细)
  9. mysql创建数据库的语法_mysql创建数据库语法
  10. 平板电脑怎么使用计算机,平板电脑怎么用
  11. Chrome 谷歌浏览器将整个网页保存为图片
  12. js让html转excel时间格式,js读取excel中日期格式转换问题
  13. HillTop (LocalScore) 算法
  14. 随手记_英语_学术写作_常用近义词区分
  15. oracle查询挂起,表挂起更新查询Oracle 11g(Table hangs on Update query Oracle 11g)
  16. *4-1 CCF 2014-12-1门禁系统
  17. 如何激励公司员工最有效?
  18. 一起谈.NET技术,.NET十年(下)
  19. 冰箱日订单数据分析报告(京东)
  20. android studio 使用CMAKE,在terminal终端里敲cmake命令

热门文章

  1. 程序员被相亲对象的账户余额吓到了!
  2. 南方人过年 VS 北方人过年
  3. 刷墙(左蓝右红或同一色)
  4. 爬虫之selenium标签页的切换
  5. 链表问题4——反转双向链表
  6. Commonjs规范
  7. Hadoop概念学习系列之Java调用Shell命令和脚本,致力于hadoop/spark集群(三十六)...
  8. 1.2 CentOS6 命令行配置静态IP地址步骤
  9. C语言中的typedef
  10. bzoj 2375: 疯狂的涂色