代码
1.添加一个请求
@RequestMapping(value = "/A", method = RequestMethod.POST)
2.在WebMvcConfigurerAdapter添加excludePathPatterns("/A")
3.添加HandlerInterceptor的实现类,并在perHandle中校验参数
问题现象
发起url="/A"的GET请求,返回参数校验失败的结果。
Debug流程
1.Http11NioProcessor类对请求进行包装处理。通过CoyoteAdapter通过管道请求转发到第一个阀门中,然后又找到其下属StandardHost,StandardHostValve阀门又将请求转发到StandardContextValve上下文对象的阀门中进行对应的处理后继续转发到StandardWrapperValve阀门。StandardWrapperValve类对应的是一个Servlet类,这里就会对请求进行具体处理了。
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
2.最终tomcat找到了DispatcherServlet,在servlet中根据HttpServletRequest获取HandlerExecutionChain对象,
在mappings中匹配请求对应handle,在RequestMappingInfoHandlerMapping进行匹配时,先匹配的url命中,但是在判断method到时候没有匹配成功,这是会在RequestMappingInfoHandlerMapping的handleNoMatch方法中抛出异常,在DispatcherServlet中进行捕获,并通过DefaultHandlerExceptionResolver将response的status设置为405
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);
}
3.层层返回每个阀门,当回到StandardHostValve时,会去获取response的status如果response是错误转状态则继续去获取错误码对应的ErrorPage,如果没有定义则获取默认的ErrorPage(/error),并重定向/error请求。
ErrorPage errorPage = context.findErrorPage(statusCode);
if (errorPage == null) {
// Look for a default error page
errorPage = context.findErrorPage(0);
}
----------------------------------------------------------------------------------------------------------------
rd.forward(request.getRequest(), response.getResponse());
4.通过阀门再次进入DispatcherServlet,这次在RequestMappingInfoHandlerMapping中成功匹配/error请求的handler,因为excludePathPatterns没有添加/error的过滤,所有/error就回进入HandlerInterceptor的perHandle方法进行校验。
tomcat启动(Ⅷ)--请求最终目的地 getContainer().getPipeline().getFirst().invoke(request, response)