关于java:遇到-400500-错误千万不要慌

40次阅读

共计 5612 个字符,预计需要花费 15 分钟才能阅读完成。

作者:fredalxin\
地址:https://fredal.xin/400-error-…

很多人都会在平时开发过程中遇到 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 或者查阅一下相干材料便能迎刃而解。

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿(2021 最新版)

2. 终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!

3. 阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!

4.Spring Cloud 2020.0.0 正式公布,全新颠覆性版本!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

正文完
 0