遇到400错误不要慌

栏目: Java · 发布时间: 6年前

内容简介:很多人都会在平时开发过程中遇到400异常,并且也没有走到服务端controller中,就变得有些不知所措。我们知道SpringMVC从DispatchServlet开始接收与分发请求,从入口开始debug,还能找不到问题所在么?从DispatchServlet的doDispatch()方法开始处理请求:

很多人都会在平时开发过程中遇到400异常,并且也没有走到服务端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或者查阅一下相关资料便能迎刃而解。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python编程

Python编程

[美]埃里克·马瑟斯 / 袁国忠 / 人民邮电出版社 / 2016-7-1 / CNY 89.00

本书是一本针对所有层次的Python 读者而作的Python 入门书。全书分两部分:第一部分介绍用Python 编程所必须了解的基本概念,包括matplotlib、NumPy 和Pygal 等强大的Python 库和工具介绍,以及列表、字典、if 语句、类、文件与异常、代码测试等内容;第二部分将理论付诸实践,讲解如何开发三个项目,包括简单的Python 2D 游戏开发如何利用数据生成交互式的信息图......一起来看看 《Python编程》 这本书的介绍吧!

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具