遇到 400、500 错误千万不要慌!

简介: 很多人都会在平时开发过程中遇到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接口约定的方法的所实现代码如下:

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 if   instanceof 判断
        else if (ex instanceof TypeMismatchException) {
            // 执行到了这里
            return handleTypeMismatch((TypeMismatchException) ex, request, response, handler);
        }
        // 删除部分else if   instanceof 判断
        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 {
 @Override
    public ModelAndView resolveException(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception exception) {
        ModelAndView model = new ModelAndView();
       // do something ...
      return model;
    } 
} 

所以遇到400错误的时候不要慌,毕竟400它是个标准的错误码,好好debug或者查阅一下相关资料便能迎刃而解。


目录
相关文章
|
7月前
https://www.shijunheng.com 现在还不通过怎么回事呢
备案还不通过原因,https://www.shijunheng.com
86 0
https://www.shijunheng.com 现在还不通过怎么回事呢
|
10月前
|
存储 人工智能
【一】曾经那些错误,你又踩坑了吗?(一)
【一】曾经那些错误,你又踩坑了吗?
40 0
|
10月前
|
存储 编译器 C++
【一】曾经那些错误,你又踩坑了吗?(二)
【一】曾经那些错误,你又踩坑了吗?
56 0
|
11月前
|
安全 小程序 程序员
删库跑路大神「后悔」了?我只不过犯了大家都会犯的编程错误!(2)
删库跑路大神「后悔」了?我只不过犯了大家都会犯的编程错误!
删库跑路大神「后悔」了?我只不过犯了大家都会犯的编程错误!(2)
|
11月前
|
Apache 云计算 开发者
删库跑路大神「后悔」了?我只不过犯了大家都会犯的编程错误!(1)
删库跑路大神「后悔」了?我只不过犯了大家都会犯的编程错误!
111 0
删库跑路大神「后悔」了?我只不过犯了大家都会犯的编程错误!(1)
|
Python
遇到bug不要慌,先发个文章看看
遇到bug不要慌,先发个文章看看
95 0
|
Java 程序员
学妹问我Java异常是怎么回事,讲了半夜才明白,速度收藏!!!记得点赞和关注
异常是Java开发中常见的,也是程序最不愿意看到的,因为有异常基本上就代表我们写的代码有bug,很烦,游戏服务端有异常上报系统,每当半夜收到异常上报都慌的一笔。今天就扒一扒异常,开始走起。
118 0
学妹问我Java异常是怎么回事,讲了半夜才明白,速度收藏!!!记得点赞和关注
|
网络协议 Linux
被鹅厂搞懵逼了(更正)
在 FIN_WAIT_2 状态下如何处理乱序的 FIN 报文
被鹅厂搞懵逼了(更正)
|
小程序 数据库
遇到问题不要慌,仔细检查帮大忙
遇到问题不要慌,仔细检查帮大忙
81 0
遇到问题不要慌,仔细检查帮大忙
|
数据可视化
7个新手数据讲述者犯下的致命错误,你都知道吗?
  本文约1800字,建议阅读5分钟。   本文介绍了新手数据讲师所犯的最常见的错误,以及如何改正它们。   在制作数据故事时,很容易迷失在细节中,并且无法创造出可以激发别人动手操作的数据故事。下面是新手数据讲师所犯的最常见的错误,以及如何改正它们。这些技巧来自“像数据讲述者一样思考”研究会。   1. 数据故事不适合听众   不是所有的听众都是相同的,不是所有的听众都有一样的目标。即使您自己审视自己团队内部,也可以考虑一个技术支持专家和一个运营主管如何具有不同的观点。尽管两者都有共同的目标即服务客户,但每个人对于这个目标能够实现的方法和原因具有不同的观点。   许多展示数据故事的讲
116 0