遇到 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或者查阅一下相关资料便能迎刃而解。


目录
相关文章
|
6月前
|
弹性计算 JavaScript Ubuntu
WebSocket协议相关的测试命令工具使用简介
本文介绍了针对WebSocket的测试工具wscat和websocat的基本使用方法,以及通过curl命令测试HTTP/HTTPS协议的方式。对于WebSocket,直接使用curl测试较为复杂,推荐使用wscat或websocat。文中详细说明了这两种工具的安装步骤、常用参数及连接示例,例如在ECS上开启8080端口监听并进行消息收发测试。此外,还提供了curl命令的手动设置头部信息以模拟WebSocket握手的示例,但指出curl仅能作为客户端测试工具,无法模拟服务器。
1564 4
|
数据采集 存储 JavaScript
Dynamic Website 爬虫:应对动态内容与 JavaScript 渲染挑战
本文深入探讨了如何设计针对动态网站的爬虫,以采集 WIPO Brand Database 中的专利和技术信息。文章详细介绍了动态网站的挑战,包括 JavaScript 渲染、反爬虫机制和异步加载,并提出了解决方案,如使用 Selenium 模拟浏览器、代理 IP 技术和 API 抓取。最后,通过具体代码示例展示了如何实现这些技术手段。
758 0
|
存储 SQL 关系型数据库
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
MySQL调优主要分为三个步骤:监控报警、排查慢SQL、MySQL调优。 排查慢SQL:开启慢查询日志 、找出最慢的几条SQL、分析查询计划 。 MySQL调优: 基础优化:缓存优化、硬件优化、参数优化、定期清理垃圾、使用合适的存储引擎、读写分离、分库分表; 表设计优化:数据类型优化、冷热数据分表等。 索引优化:考虑索引失效的11个场景、遵循索引设计原则、连接查询优化、排序优化、深分页查询优化、覆盖索引、索引下推、用普通索引等。 SQL优化。
1691 15
【MySQL调优】如何进行MySQL调优?从参数、数据建模、索引、SQL语句等方向,三万字详细解读MySQL的性能优化方案(2024版)
|
自动驾驶 物联网 5G
5G网络的演进:从理论到实践
【10月更文挑战第3天】5G网络作为新一代移动通信技术,不仅在理论上实现了重大突破,而且在实践中也展现出了强大的生命力。本文将围绕5G网络的演进,从理论基础到实际应用,探讨5G技术的发展和实践案例,同时提供代码示例以供参考。
625 6
|
Rust 安全 编译器
30天拿下Rust之语法大全
Rust是一种系统级编程语言,以其独特的所有权系统和内存安全性受到开发者青睐。本文从基本数据类型入手,介绍了标量类型如整数、浮点数、布尔值及字符,复合类型如元组、数组和结构体等。此外,还探讨了变量与常量的声明与使用,条件判断与循环语句的语法,以及函数定义与调用的方法。文章通过示例代码展示了如何使用Rust编写简洁高效的程序,并简要介绍了注释与宏的概念,为读者快速掌握这门语言提供了实用指南。欲获取最新文章或交流技术问题,请关注微信公众号“希望睿智”。
320 1
|
Shell 开发工具 git
如何使用git上传代码github仓库
如何使用git上传代码github仓库
|
消息中间件 弹性计算 监控
【Serverless架构组成及优势适用场景】
Serverless的弹性伸缩、按需计费、无状态等特性使得开发者能够更加专注于业务逻辑,摆脱繁琐的服务器管理。它的优势在于灵活应对突发性工作负载、降低成本、提高开发效率,尤其在事件驱动、微服务、后端API等场景中表现出色。虽然Serverless仍然在不断发展,但其已经在云计算领域掀起了一场革命,成为当今应用开发的热门选择。随着技术的不断演进,我们有理由期待Serverless将继续推动应用开发的创新,为我们构建更加高效、可靠的应用提供更多可能。
593 0
|
API 文件存储
使用Streamlit创建AutoGen用户界面
AutoGen作为一个最大化LLM(如GPT-4)能力的框架而脱颖而出。由微软研究院开发的AutoGen通过提供一种自动化、优化和编排工作流的方法,简化了复杂的、基于多代理llm的应用程序的创建。我们在以前的文章中也有过介绍,你可以与许多GPT交谈,并且GPT和GPT之间也可以互相交谈。每个GPT都是它自己的“代理”,并在总体业务流程中扮演特殊角色。但是AutoGen是用命令行模式进行交互的,这对我们的输入来说非常不方便,所以这次我们来对其进行改造,使用Streamlit创建一个web界面,这样可以让我们更好的与其交互。
720 1
|
机器学习/深度学习 人工智能 监控
【AI 现况分析】AI 大模型在自动化交易的应用
【1月更文挑战第27天】【AI 现况分析】AI 大模型在自动化交易的应用
|
存储 缓存 运维
解密一致性哈希算法:实现高可用和负载均衡的秘诀
解密一致性哈希算法:实现高可用和负载均衡的秘诀
1659 0