Spring Boot统一异常处理的拦截指南
通常我们在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统一异常处理的拦截指南相关推荐
- Spring Boot统一异常处理实践
Spring Boot统一异常处理实践 参考文章: (1)Spring Boot统一异常处理实践 (2)https://www.cnblogs.com/fundebug/p/springboot-ex ...
- Spring Boot 统一功能处理(用户登录权限效验-拦截器、异常处理、数据格式返回)
文章目录 1. 统一用户登录权限效验 1.1 最初用户登录权限效验 1.2 Spring AOP 统一用户登录验证 1.3 Spring 拦截器 1.4 练习:登录拦截器 1.5 拦截器实现原理 1. ...
- Spring Boot默认异常处理BasicErrorController源码解读
小伙伴们是不是刚接触Spring Boot做网页开发的时候,如果代码发生异常,会返回一个错误信息页面,如下图 那么这个页面是怎么返回的呢,这里就要接触到一个Spring Boot类BasicError ...
- Spring Boot 统一功能处理
Spring Boot 统一功能处理 一.使用 Spring 拦截器来实现登录验证 引入 代码实现 步骤1 自定义拦截器 步骤2 添加拦截器并设置拦截规则 拦截规则 步骤3 创建前后端交互,用于测试 ...
- Spring MVC统一异常处理
Spring MVC统一异常处理 一.为什么需要统一异常处理? 1.1 try catch带来的问题 平时项目中处理Controller层异常很多时候都会使用try catch去捕获异常(包括Cont ...
- 编程小白入门分享三:Spring AOP统一异常处理
编程小白入门分享三:Spring AOP统一异常处理 参考文章: (1)编程小白入门分享三:Spring AOP统一异常处理 (2)https://www.cnblogs.com/lxk12345/p ...
- spring mvc统一异常处理(@ControllerAdvice + @ExceptionHandler)
spring mvc统一异常处理(@ControllerAdvice + @ExceptionHandler) 参考文章: (1)spring mvc统一异常处理(@ControllerAdvice ...
- spring boot 全局异常处理的实现(@ExceptionHandler),以及@InitBinder、@ModelAttribute的作用
spring boot 全局异常处理的实现(@ExceptionHandler),以及@InitBinder.@ModelAttribute的作用 参考文章: (1)spring boot 全局异常处 ...
- Spring Boot 全局异常处理(400/404/500),顺便解决过滤器中异常未捕获到的问题,让RestApi 任何时候都能获取统一的格式代码
出发点是为了在系统抛出异常的时候,前端仍然可以获取到统一的报文格式,所以后端所有的异常都得捕获,并处理 Spring boot 在处理异常的时候,500/404默认都会转发到/error,而这个异常的 ...
最新文章
- rfc6455 WebSockets
- JS 获取 鼠标 坐标
- MySQL命令窗口出现中文乱码的解决方法
- 标准模板库 STL—— set 列传
- 回斯坦福之后研究成果曝光,李飞飞团队用机器学习教机械臂做动作
- 4.企业安全建设指南(金融行业安全架构与技术实践) --- 内控合规管理
- 线程知识点——Event事件
- C语言贪吃蛇 新手入门(超详细)
- mysql创建数据库的语法_mysql创建数据库语法
- 平板电脑怎么使用计算机,平板电脑怎么用
- Chrome 谷歌浏览器将整个网页保存为图片
- js让html转excel时间格式,js读取excel中日期格式转换问题
- HillTop (LocalScore) 算法
- 随手记_英语_学术写作_常用近义词区分
- oracle查询挂起,表挂起更新查询Oracle 11g(Table hangs on Update query Oracle 11g)
- *4-1 CCF 2014-12-1门禁系统
- 如何激励公司员工最有效?
- 一起谈.NET技术,.NET十年(下)
- 冰箱日订单数据分析报告(京东)
- android studio 使用CMAKE,在terminal终端里敲cmake命令