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或者查閱一下相關資料便能迎刃而解。