如何应对spring框架的HTTP ERROR 400 Bad Request错误返回问题
HTTP ERROR 400 Bad Request 产生的流程
在使用springmvc相关的框架的时候,调用接口经常产生以下错误

这种错误往往在info的log级别下看不到日志,难以排查,我们先来模拟错误产生的其中一个原因
从spring框架的入口FrameworkServlet开始找
1.假设我们的接口使用get请求,则从doGet里面的processRequest方法开始调式,并且假设模拟一个请求类型不匹配的参数,比如需要一个int类型的参数但是传一个字符串。


2.下一步进入doDispatch方法

3.进入接口对应方法的处理,使用handler处理

4.进入到实际调用的方法的代码,invokeHandleMethod,在调用此方法的时候,会先做一些参数的校验,如是否空值(MissingServletRequestParameterException)、是否类型匹配(TypeMismatchException)、媒体类型是否支持(HttpMediaTypeNotSupportedException)等

5.进入invokeForRequest方法

6.进入getMethodArgumentValues方法,此方法用来获取处理接口实际方法的参数和值的对应关系。
可以看到在这个地方产生了错误,并且向上一级抛出了异常且异常被doDispatch捕获,然后进入processDispatchResult方法处理返回的结果


7.调用HandlerExecutionChain的异常处理方法去处理异常

8.调用resolveException处理,处理的时候是循环使用List<HandlerExceptionResolver> resolvers中的所有的handlerExceptionResolver依次处理,如果处理成功则返回。
可以看到一共有5个handlerExceptionResolver,本次接口调用被第二个handlerExceptionResolver处理成功并返回


9.异常被成功处理

10.返回错误码和空ModelAndView

11.在request的Attribute属性中设置异常信息

12.进行handler的后置处理,比如执行HandlerInterceptor的afterCompletion方法

13.执行processRequest的finally中的剩余代码逻辑

HTTP ERROR 400 Bad Request 产生的原因
由于在以上代码中调用了
response.sendError(HttpServletResponse.SC_BAD_REQUEST); return new ModelAndView();
导致产生了400页面
400错误为什么不能被自定义的异常处理器捕获并且处理
由于handlerExceptionResolvers要按顺序依次执行并且执行成功后就立即返回后续的将不再执行,我们自定义的handlerExceptionResolvers排在List的最后(由上图可以很清晰的知道,我们自定义的WebExceptionHandler排在最后),所以,轮不到它处理,spring就内部就将异常消化处理好了。
为什么不能自己定制输出内容
response.sendError(HttpServletResponse.SC_BAD_REQUEST)
上面的代码已经使用了response将结果写入到输出流,所以后续将无法使用response或者类似于
PrintWriter out = null;
try {
out = response.getWriter();
Map<String,Object> result = new HashMap<String, Object>();
result.put("code",be.getErrorCode());
result.put("message",be.getMessage());
out.write(JSONObject.toJSONString(result));
out.flush();
} catch (IOException e) {
} finally {
if (out != null) {
out.close();
out = null;
}
}
的方式自定义输出
目前可以做的
研究了一番,发现不能自定义输出(或者有其他的好方法没发现),所以只能记录下错误日志并且打印出来,这样就不会稀里糊涂了
未加日志之前

加日志之后


如何加日志
通过以上的代码分析可知,spring会将异常写入到request的Attribute属性中,所以只需要
Object attribute = request.getAttribute(DispatcherServlet.class.getName() + ".EXCEPTION");
就可以获得异常信息了,并且在自己的Filter里面打印,这样就不会在产生400之类类似的错误的时候一头雾水了
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
Spring Boot源码实现StopWatch优雅统计耗时
这篇文章主要为大家介绍了Spring Boot源码实现StopWatch优雅统计耗时,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2022-07-07
基于JavaSwing+mysql开发一个学生社团管理系统设计和实现
项目使用Java swing+mysql开发,可实现基础数据维护、用户登录注册、社团信息列表查看、社团信息添加、社团信息修改、社团信息删除以及退出注销等功能、界面设计比较简单易学、适合作为Java课设设计以及学习技术使用,需要的朋友参考下吧2021-08-08
Ubuntu手动安装JDK 17完整教程(.tar.gz 方式)
JDK是Java开发的核心组件之一,它包含了Java编译器和Java运行时环境,以及其他开发工具和库,这篇文章主要介绍了Ubuntu手动安装JDK 17(.tar.gz 方式)的相关资料,需要的朋友可以参考下2026-02-02


最新评论