一 异常测试:
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(); }
原文地址:https://www.cnblogs.com/brant/p/9415726.html