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


目录
相关文章
|
11月前
|
弹性计算 JavaScript Ubuntu
WebSocket协议相关的测试命令工具使用简介
本文介绍了针对WebSocket的测试工具wscat和websocat的基本使用方法,以及通过curl命令测试HTTP/HTTPS协议的方式。对于WebSocket,直接使用curl测试较为复杂,推荐使用wscat或websocat。文中详细说明了这两种工具的安装步骤、常用参数及连接示例,例如在ECS上开启8080端口监听并进行消息收发测试。此外,还提供了curl命令的手动设置头部信息以模拟WebSocket握手的示例,但指出curl仅能作为客户端测试工具,无法模拟服务器。
3602 5
|
11月前
|
存储 安全 Java
2025 年最新 40 个 Java 基础核心知识点全面梳理一文掌握 Java 基础关键概念
本文系统梳理了Java编程的40个核心知识点,涵盖基础语法、面向对象、集合框架、异常处理、多线程、IO流、反射机制等关键领域。重点包括:JVM运行原理、基本数据类型、封装/继承/多态三大特性、集合类对比(ArrayList vs LinkedList、HashMap vs TreeMap)、异常分类及处理方式、线程创建与同步机制、IO流体系结构以及反射的应用场景。这些基础知识是Java开发的根基,掌握后能为后续框架学习和项目开发奠定坚实基础。文中还提供了代码资源获取方式,方便读者进一步实践学习。
2769 2
|
Java
Java集合Stream类filter的使用
Java集合Stream类filter的使用
392 0
|
Java 数据库连接 数据库
深入理解 Java Bean 的生命周期及各个阶段解析
深入理解 Java Bean 的生命周期及各个阶段解析
|
Unix Linux
linux进程之fork 和 exec函数
---恢复内容开始--- fork函数 该函数是unix中派生新进程的唯一方法。   #include    pid_t   fork(void); 返回: (调用它一次, 它返回 两次 , 它在调用进程(称为父进程)中返回一次, 返回值是新派生进程(称为子进程)的进程ID号     在子进程又返回一次,返回值为0。
1494 0
|
11天前
|
人工智能 开发工具 iOS开发
Claude Code 新手完全上手指南:安装、国产模型配置与常用命令全解
Claude Code 是一款运行在终端环境中的 AI 编程助手,能够直接在命令行中完成代码生成、项目分析、文件修改、命令执行、Git 管理等开发全流程工作。它最大的特点是**任务驱动、终端原生、轻量高效、多模型兼容**,无需图形界面、不依赖 IDE 插件,能够深度融入开发者日常工作流。
3295 10
|
3天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
1663 5
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
|
14天前
|
Shell API 开发工具
Claude Code 快速上手指南(新手友好版)
AI编程工具卷疯啦!Claude Code凭借任务驱动+终端原生的特性,成了开发者的效率搭子。本文从安装、登录、切换国产模型到常用命令,手把手带新手快速上手,全程避坑,30分钟独立用起来。
3347 24
|
7天前
|
人工智能 Linux BI
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek
JeecgBoot AI专题研究 一键脚本:Claude Code + JeecgBoot Skills + DeepSeek 全平台接入 一行命令装好 Claude Code + JeecgBoot Skills + DeepSeek 接入,无需翻墙使用 Claude Code,支持 Wind
2386 4
国内用 Claude Code 终于不用翻墙了:一行命令搞定,自动接 DeepSeek

热门文章

最新文章