Spring Cloud-17-Zuul异常处理源码分析

本文来看一下Zuul的异常处理流程,以及如何自定义异常信息

Zuul生命周期

看一下官方给出的Zuul请求的生命周期图:
image

从图上可以看出,正常情况下,请求都是按照pre→route→post的顺序来执行,最后由post返回response.

在看一下pre下面的custom filter,就是说在pre阶段,如果有用户自定义的过滤器则执行自定义的过滤器.

pre routing post的任意一个阶段如果抛异常了,则执行error过滤器,然后再执行post给出响应.

源码分析

来看下源码com.netflix.zuul.http.ZuulServlet这个类中的service方法,是整个调用过程的核心:
image

可以看到,内层的3个catch只捕获ZuulException这个异常,其他的异常是交给外层的catch去捕获.

pre和route执行出错之后都会先执行error再执行post,而post执行出错之后就只执行error而不会再执行post.

ZuulFilter最终会在com.netflix.zuul.FilterProcessor的processZuulFilter方法中被调用,在该方法中会判断runFilter是否执行成功,如果执行失败,则将异常信息提取出来,然后抛出异常,抛出的异常如果是ZuulException的实例,则抛出一个ZuulException类型的异常,如果不是ZuulException的实例,则抛出一个状态码为500的ZuulException类型的异常,所以无论如何,我们最终看到的都是ZuulException类型的异常,下面我贴出processZuulFilter方法的代码,如下:
image

再看下runfilter这个方法:
image

在Zuul中,所有的错误问题的最终都是被SendErrorFilter类来处理,该类在早期的版本是一个post类型的filter,post类型的filter有一个缺陷就是不能处理post中抛出的异常,需要我们手动去完善,而我目前使用的这个版本(Dalston.SR3)已经修复了这个问题,SendErrorFilter现在是一个error类型的filter,而且只要RequestContext中有异常就会进入到SendErrorFilter中,错误信息也都从exception对象中提取出来,核心代码如下:
image

自定义异常信息

创建一个类,继承DefaultErrorAttributes类,然后重写getErrorAttributes 方法,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
public class MyErrorAttribute extends DefaultErrorAttributes {
@Override
public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
Map<String, Object> map = super.getErrorAttributes(requestAttributes, includeStackTrace);
map.put("status", 222);
map.put("error", "error");
map.put("exception", "exception");
map.put("message", "message");
return map;
}
}