作者:fredalxin
地址:https://fredal.xin/400-error-deal
很多人都会在平时开发过程中遇到400或500异常 , 并且也没有走到服务端controller中 , 就变得有些不知所措 。
我们知道SpringMVC从DispatchServlet开始接收与分发请求 , 从入口开始debug , 还能找不到问题所在么?
从DispatchServlet的doDispatch()方法开始处理请求:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {//删除一些代码try {ModelAndView mv = null;Exception dispatchException = null;try {// 删除一些代码try {// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());}finally {if (asyncManager.isConcurrentHandlingStarted()) {return;}}applyDefaultViewName(request, mv);mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException = ex;// 这里捕获了异常TypeMismatchException}processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {}finally {// 删除一些代码}}其实在这儿我们就能看到exception的具体异常栈 , 有兴趣的可以继续看springMVC的处理方法processDispatchResult 。
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {boolean errorView = false;if (exception != null) {if (exception instanceof ModelAndViewDefiningException) {logger.debug("ModelAndViewDefiningException encountered", exception);mv = ((ModelAndViewDefiningException) exception).getModelAndView();}else {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);mv = processHandlerException(request, response, handler, exception);// 执行这个方法errorView = (mv != null);}}// 方便阅读 , 删除了其他代码}这个方法中对异常进行判断 , 发现不是“ModelAndViewDefiningException”就交给processHandlerException方法继续处理 。
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {// Check registered HandlerExceptionResolvers...ModelAndView exMv = null;for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);if (exMv != null) {break;}}// 去掉了一些代码throw ex;}这里看到for循环来找一个handlerExceptionResolver来处理这个异常 。handler列表有spring自带的ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver以及自定义的exceptionResolver 。
这些都继承自AbstractHandlerExceptionResolver类 , 这个类是一个抽象类 , 它实现了HandlerExceptionResolver接口 , 它对HandlerExceptionResolver接口约定的方法的所实现代码如下:
【遇到 400、500 错误千万不要慌!】public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {if (shouldApplyTo(request, handler)) {logException(ex, request);prepareResponse(ex, response);return doResolveException(request, response, handler, ex);}else {return null;}}首先判断当前异常处理器是否可以处理当前的目标handler 。例如通过for循环依次发现轮到DefaultHandlerExceptionResolver才能处理 , 那么最终会执行该handlerExceptionResolver的doResolveException方法 。
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {try {if (ex instanceof NoSuchRequestHandlingMethodException) {return handleNoSuchRequestHandlingMethod(...);}// 删除部分else ifinstanceof 判断else if (ex instanceof TypeMismatchException) {// 执行到了这里return handleTypeMismatch((TypeMismatchException) ex, request, response, handler);}// 删除部分else ifinstanceof 判断else if (ex instanceof BindException) {return handleBindException((BindException) ex, request, response, handler);}}catch (Exception handlerException) {}return null;}通过对异常类型的判断 , 来执行相应handleXXXException方法 。而handleXXXException方法中 , 有很多是会抛出400错误的!
举个几个栗子:
protected ModelAndView handleMissingServletRequestParameter(MissingServletRequestParameterException ex, HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {response.sendError(400, ex.getMessage());return new ModelAndView();}protected ModelAndView handleServletRequestBindingException(ServletRequestBindingException ex, HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {response.sendError(400, ex.getMessage());return new ModelAndView();}protected ModelAndView handleTypeMismatch(TypeMismatchException ex, HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {response.sendError(400);return new ModelAndView();}protected ModelAndView handleHttpMessageNotReadable(HttpMessageNotReadableException ex, HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {response.sendError(400);return new ModelAndView();}protected ModelAndView handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {response.sendError(400);return new ModelAndView();}protected ModelAndView handleMissingServletRequestPartException(MissingServletRequestPartException ex, HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {response.sendError(400, ex.getMessage());return new ModelAndView();}protected ModelAndView handleBindException(BindException ex, HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {response.sendError(400);return new ModelAndView();}那么抛出400错误的时候该怎么解决呢?
从服务端角度出发 , 可以定义完善的全局异常处理器exceptionHandler , 把易抛出400的错误例如TypeMismatchException、BindException都给处理掉 , 返回能看得懂的信息 。
从客户端请求过程中来看 , 可以自定义handlerExceptionResolver , 只需实现HandlerExceptionResolver接口即可 , 例如:
public class ApiHandlerExceptionResolver implements HandlerExceptionResolver { @Overridepublic ModelAndView resolveException(HttpServletRequest request,HttpServletResponse response, Object handler, Exception exception) {ModelAndView model = new ModelAndView();// do something ...return model;} } 所以遇到400错误的时候不要慌 , 毕竟400它是个标准的错误码 , 好好debug或者查阅一下相关资料便能迎刃而解 。
近期热文推荐:
1.1,000+ 道 Java面试题及答案整理(2021最新版)
2.终于靠开源项目弄到 IntelliJ IDEA 激活码了 , 真香!
3.阿里 Mock 工具正式开源 , 干掉市面上所有 Mock 工具!
4.Spring Cloud 2020.0.0 正式发布 , 全新颠覆性版本!
5.《Java开发手册(嵩山版)》最新发布 , 速速下载!
觉得不错 , 别忘了随手点赞+转发哦!
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
