内容简介:很多人都会在平时开发过程中遇到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或者查阅一下相关资料便能迎刃而解。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- 在开发 Web 程序时常遇到的错误
- GO常见的错误99%程序员会遇到
- MySQL DBA如何"土土"地利用源码解决没有遇到过的错误?
- 没遇到过这十个MySQL数据库经典错误,你一定不是个好工程师
- 遇到的加密算法
- 静态库遇到静态库
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Python编程
[美]埃里克·马瑟斯 / 袁国忠 / 人民邮电出版社 / 2016-7-1 / CNY 89.00
本书是一本针对所有层次的Python 读者而作的Python 入门书。全书分两部分:第一部分介绍用Python 编程所必须了解的基本概念,包括matplotlib、NumPy 和Pygal 等强大的Python 库和工具介绍,以及列表、字典、if 语句、类、文件与异常、代码测试等内容;第二部分将理论付诸实践,讲解如何开发三个项目,包括简单的Python 2D 游戏开发如何利用数据生成交互式的信息图......一起来看看 《Python编程》 这本书的介绍吧!