• Spring cloud Zuul网关异常处理


    Spring cloud Zuul网关异常处理

    一 异常测试: 

    1> 创建一个pre类型的过滤器,并在该过滤器的run方法实现中抛出一个异常。比如下面的实现,在run方法中调用的doSomething方法将抛出RuntimeException异常

    package com.xbchen.springcloud.filter.post;
    
    import com.netflix.zuul.ZuulFilter;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    
    @Component
    public class ThrowExceptionPostFilter extends ZuulFilter  {
    
        private static Logger log = LoggerFactory.getLogger(ThrowExceptionPostFilter.class);
    
        @Override
        public String filterType() {
            return "post";
        }
    
        @Override
        public int filterOrder() {
            return 10;
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        @Override
        public Object run() {
            log.info("This is a post filter, it will throw a RuntimeException");
            doSomething();
            return null;
        }
    
        private void doSomething() {
            throw new RuntimeException("Exist some errors...");
        }
    
    }

    2> 在启动类中为过滤器创建Bean

    @Bean
    public ThrowExceptionFilter throwExceptionFilter() {
      return new ThrowExceptionFilter();
    }

    3> 运行启动类

    4> 发现后台并没抛出异常信息

                                                                                                                                                  

    二 问题分析:

    查看postRoute阶段的异常处理过滤器SendErrorFilter中的方法shouldFilter

     

    注意: 新版本中已经修复了该问题,取消了error.status_code的判断。

    即: 只有上线文中包含error.status_code,才能被SendErrorFilter处理。

    以此需要自行处理。

    处理方式1: 在抛异常时,自行捕获设置error.status_code

    @Override
    public Object run() {
        log.info("This is a post filter, it will throw a RuntimeException");
        //doSomething();
        RequestContext context=RequestContext.getCurrentContext();
        try{
            doSomething();
        }catch (Exception e){
            context.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            context.set("error.exception",3);
        }
        return null;
    }

    处理方式2:新增一个error处理的过滤器

    @Component
    public class ErrorFilter extends ZuulFilter {
        Logger log = LoggerFactory.getLogger(ErrorFilter.class);
        @Override
        public String filterType() {
            return "error";
        }
        @Override
        public int filterOrder() {
            return 20;
        }
        @Override
        public boolean shouldFilter() {
            return true;
        }
        @Override
        public Object run() {
            RequestContext ctx = RequestContext.getCurrentContext();
            Throwable throwable = RequestContext.getCurrentContext().getThrowable();
            log.error("this is a ErrorFilter : {}", throwable.getCause().getMessage());
            ctx.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            ctx.set("error.exception", throwable.getCause());
            return null;
        }
    
    }

    三:遗留问题:路由包括3阶段, 正常处理过程:preRoute-->route-->postRoute

    其中preRoute 和route异常时,会被捕获直接进入postRoute;

    会经过postRoute的过滤器(SendErrorFilter extends ZuulFilter)

    但是postRoute阶段的异常,是没有处理的过滤器的。以此需要针对postRoute阶段的异常进行单独处理。

    处理方式:

    新增处理类,扩展过滤器处理类FilterProcessor的processZuulFilter方法

    public class DidiFilterProcessor extends FilterProcessor {
    
        @Override
        public Object processZuulFilter(ZuulFilter filter) throws ZuulException {
            try {
                return super.processZuulFilter(filter);
            } catch (ZuulException e) {
                RequestContext ctx = RequestContext.getCurrentContext();
                ctx.set("failed.exception", e);
                ctx.set("failed.filter", filter);
                throw e;
            }
        }
    }

    在启动类中设置处理类

    @SpringBootApplication
    @EnableZuulProxy
    public class GatewayApplication {
    
      public static void main(String[] args) {
        FilterProcessor.setProcessor(new DidiFilterProcessor());
        SpringApplication.run(GatewayApplication.class, args);
      }
    }

    新增post阶段的异常处理过滤器

    /**
     * 从POST抛出的异常,使用该过滤器返回错误信息
     */
    @Component
    public class ErrorExtFilter extends SendErrorFilter {
        Logger log = LoggerFactory.getLogger(ErrorExtFilter.class);
        @Override
        public String filterType() {
            return "error";
        }
        @Override
        public int filterOrder() {
            return 30;
        }
        @Override
        public boolean shouldFilter() {
            RequestContext ctx = RequestContext.getCurrentContext();
            ZuulFilter failedFilter = (ZuulFilter) ctx.get("failed.filter");
            if(failedFilter != null && failedFilter.filterType().equals("post")) {
                return true;
            }
            return false;
        }
    }

    四:异常自定义

    以上异常已经正常抛出,但是格式并不一定符合项目要求,或者有时并不需要将异常返回给客户端。

    由于异常信息格式是在DefaultErrorAttributes定义的,以此可对该类进行扩展。

    比如:异常异常信息,避免返回到客户端。

    public class DidiErrorAttributes extends DefaultErrorAttributes {
    
        @Override
        public Map<String, Object> getErrorAttributes (
                RequestAttributes requestAttributes, boolean includeStackTrace){
            Map<String, Object> result = super.getErrorAttributes(requestAttributes, includeStackTrace);
            result.remove("exception");
            return result;
        }
    }


    在启动类中新增异常属性扩展类的Bean创建。

    @Bean
      public DefaultErrorAttributes errorAttributes() {
        return new DidiErrorAttributes();
      }
  • 相关阅读:
    10.28
    10.25
    10.21
    移动第七次作业
    移动第六次作业
    移动第五次作业
    移动第四次作业
    移动第3次作业
    移动第二次作业
    移动第一次作业
  • 原文地址:https://www.cnblogs.com/brant/p/9415726.html
Copyright © 2020-2023  润新知