美文网首页
SpringMVC ErrorPage粗解

SpringMVC ErrorPage粗解

作者: 丑人林宗己 | 来源:发表于2021-02-10 15:51 被阅读0次

    起因

    最近观察生产日志发现偶尔会看到一个/error接口的错误异常,但是从异常堆栈信息里没有找到任何关于真实发生错误的接口路径,以至于排查问题时无从下手。

    通过Postman复现一下,效果如下:

    image.png

    带着如下几个问题来拆分ErrorPage的实现方式:

    • 什么场景会触发ErrorPage页面
    • ErrorPage的实现核心组件包括哪些

    ErrorController

    通过查找,定位到自己代码依赖着一个自实现的common包,其中有个CustomerErrorController,其访问路径为:

    ${server.error.path:${error.path:/error}}
    

    在配置文件没有配置server.error.path以及error.path时,路径为/error,逻辑上符合复现的场景,通过debug也确实可以证实。

    CustomerErrorController网上找最终发现顶级接口就是ErrorController,利用IDEA工具可以快速看到默认实现的类

    @Controller
    @RequestMapping("${server.error.path:${error.path:/error}}")
    public class BasicErrorController extends AbstractErrorController{  ...  }
    
    @Bean
    @ConditionalOnMissingBean(value = ErrorController.class, search = SearchStrategy.CURRENT)
    public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
        return new BasicErrorController(errorAttributes, this.serverProperties.getError(),
                this.errorViewResolvers);
    }
    

    ServerProperties中找到ErrorProperties,其中默认配置的path/error,与CustomerErrorController的路径是相同的。

    ErrorMvcAutoConfiguration

    /// 核心的组件
    ErrorPageCustomizer
    ErrorPageRegistrarBeanPostProcessor
    ErrorPageFilter
    TomcatEmbeddedServletContainerFactory
    TomcatErrorPage
    
    // 在ErrorPageFilter中找到
    private void setErrorAttributes(HttpServletRequest request, int status,
            String message) {
        request.setAttribute(ERROR_STATUS_CODE, status);
        request.setAttribute(ERROR_MESSAGE, message);
        // 获取到uri就可以知道是哪个接口触发了这段跳转至/error接口
        request.setAttribute(ERROR_REQUEST_URI, request.getRequestURI());
    }
    
    // 这几个参数在自定义的ErrorController中是可以读取到,
    // 但是通过Debug发现并没有运行到ErrorPageFilter,
    // 意味着类似的代码可能在另外的地方也有一份
    
    

    回到前文提到的两个问题。

    什么场景会触发ErrorPage?由于没有找到真正核心的代码,参考ErrorPageFilter的代码如下:(想要一探究竟,考虑从DispatchServlet的流程上去找)

    private void doFilter(HttpServletRequest request, HttpServletResponse response,
                FilterChain chain) throws IOException, ServletException {
            ErrorWrapperResponse wrapped = new ErrorWrapperResponse(response);
            try {
                chain.doFilter(request, wrapped);
                if (wrapped.hasErrorToSend()) {
                    handleErrorStatus(request, response, wrapped.getStatus(),
                            wrapped.getMessage());
                    response.flushBuffer();
                }
                else if (!request.isAsyncStarted() && !response.isCommitted()) {
                    response.flushBuffer();
                }
            }
            catch (Throwable ex) {
                Throwable exceptionToHandle = ex;
                if (ex instanceof NestedServletException) {
                    exceptionToHandle = ((NestedServletException) ex).getRootCause();
                }
                handleException(request, response, wrapped, exceptionToHandle);
                response.flushBuffer();
            }
        }
    

    ErrorPage包括哪些核心组件?参照ErrorMvcAutoConfiguration

    相关文章

      网友评论

          本文标题:SpringMVC ErrorPage粗解

          本文链接:https://www.haomeiwen.com/subject/ldahxltx.html