常请求处理流程 发送/error请求以及得到error视图的详细原理

Spring MVC SpringBoot源码解析:异常请求处理流程;发送/error并返回error视图的详细原理

引言

一个错误请求的处理流程主要是这样的:

  1. 当发送一个错误请求时,spring mvc会尝试处理这个请求,比如尝试去寻找静态资源等等;

  2. 如果处理失败,会将错误信息保存,然后重新发送一个/error请求;

  3. /error请求会被errorController处理,返回一个error视图;

本文主要通过源码分析异常请求处理的整个流程,对于springboot提供的BasicErrorController等解析error的组件不做过多描述;

SpringBoot默认处理规则

默认情况下,Spring Boot提供 “/error” 处理所有错误的映射(BasicErrorController);

对于机器客户端,它将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息;

在这里插入图片描述

对于浏览器客户端,响应一个“ whitelabel”错误视图,以HTML格式呈现相同的数据;

在这里插入图片描述

不论error html页面还是error json,能够得到的属性是一样的,有:

timestamp, status, error, exception, message, errors, trace, path

*异常请求处理流程

异常请求处理的流程主要分成四步:

  1. 解析错误请求被作为异常抛出
  2. 尝试处理错误请求
  3. 如果处理失败,会给底层response发送错误信息;然后再重新发送一个/error请求
  4. /error请求被ErrorController处理(SpringBoot帮我们自动配置了BasicErrorController)

步骤一:将错误请求作为异常抛出

当发送请求时,DispatcherServlet的doDispatch方法会寻找合适的Handler,然后通过Handler去找合适的Adapter去最终处理这个请求;

当发送错误请求时,寻找Handler过程就会抛出异常并被catch捕获;

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   
    ...
		catch (Exception ex) {
   
   			dispatchException = ex;
		}
	processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    ...

捕获的异常会调用processDispatchResult尝试处理异常;

例:当发送一个405请求:Method Not Allowed,

部分栈轨迹:

handleNoMatch:250, RequestMappingInfoHandlerMapping (org.springframework.web.servlet.mvc.method)
lookupHandlerMethod:417, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
getHandlerInternal:364, AbstractHandlerMethodMapping (org.springframework.web.servlet.handler)
getHandlerInternal:123, RequestMappingInfoHandlerMapping (org.springframework.web.servlet.mvc.method)
getHandlerInternal:66, RequestMappingInfoHandlerMapping (org.springframework.web.servlet.mvc.method)
getHandler:491, AbstractHandlerMapping (org.springframework.web.servlet.handler)
getHandler:1255, DispatcherServlet (org.springframework.web.servlet)
doDispatch:1037, DispatcherServlet (org.springframework.web.servlet)
doService:961, DispatcherServlet (org.springframework.web.servlet)
processRequest:1006, FrameworkServlet (org.springframework.web.servlet)
doGet:898, FrameworkServlet (org.springframework.web.servlet)
service:626, HttpServlet (javax.servlet.http)
service:883, FrameworkServlet (org.springframework.web.servlet)
service:733, HttpServlet (javax.servlet.http)

最终handleNoMatch方法抛出HttpRequestMethodNotSupportedException:

@Override
protected HandlerMethod handleNoMatch(
      Set<RequestMappingInfo> infos, String lookupPath, HttpServletRequest request) throws ServletException {

   PartialMatchHelper helper = new PartialMatchHelper(infos, request);
   if (helper.isEmpty()) {
      return null;
   }

   if (helper.hasMethodsMismatch()) {
      Set<String> methods = helper.getAllowedMethods();
      if (HttpMethod.OPTIONS.matches(request.getMethod())) {
         HttpOptionsHandler handler = new HttpOptionsHandler(methods);
         return new HandlerMethod(handler, HTTP_OPTIONS_HANDLE_METHOD);
      }
      throw new HttpRequestMethodNotSupportedException(request.getMethod(), methods);
   }

步骤二:尝试处理异常

抛出的异常都会被DispatcherServlet.doDispatch的catch捕获到,然后带着这个异常信息调用processDispatchResult方法:

这个方法首先会尝试处理异常信息去获取ModelAndView对象:

该方法的主要逻辑:

  1. 寻找能够处理异常的对象:如果是ModelAndView定义异常,会返回一个特殊的视图(表明视图定义异常);否则,说明是handler的异常,会调用processHandlerException处理(具体看下面该方法的处理流程);
  2. 如果最终成功处理了异常,会得到ModelAndView对象,然后将视图渲染,处理完成;否则抛出异常。
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
      @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
      @Nullable Exception exception) throws Exception {
   

   boolean errorView = false;

   if (exception != null) {
   
      if (exception instanceof ModelAndViewDefiningException) {
   
         logger.debug("ModelAndViewDefiningException encountered", exception);
         mv = ((ModelAndViewDefiningException) exception).getModelAndView(
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值