标签:返回 Filter Zuul 请求 Netflix filter 源码 过滤器 filterOrder
Zuul 是 Spring Cloud 集成 Netflix-Zuul 的一个微服务网关.
Zuul 中集成了NetFlix的Ribbon负载
Zuul 核心 ZuulFilter,通过Zuul底层利用各种Filter可以实现不同的需求,也可自定义实现.
Spring官网Zuul文档:
https://docs.spring.io/spring-cloud-netflix/docs/2.2.6.RELEASE/reference/html/#router-and-filter-zuul
主要功能
- 认证和安全 识别每个需要认证的资源,拒绝不符合要求的请求。
- 性能监测 在服务边界追踪并统计数据,提供精确的生产视图。
- 动态路由 根据需要将请求动态路由到后端集群。
- 压力测试 逐渐增加对集群的流量以了解其性能。
- 负载卸载 预先为每种类型的请求分配容量,当请求超过容量时自动丢弃。
- 静态资源处理 直接在边界返回某些响应。
顶层是IZuulFilter接口,有两个方法
1. boolean shouldFilter();
作用:判断是否要过滤,返回true会执行过滤,调用run()方法
2.Object run() throws ZuulException;
作用:核心执行的方法,在run中重写自己的逻辑
抽象类ZuulFilter实现了IZuulFilter接口,包含几个核心方法,一般实现自定义ZuulFlter,继承此抽象类即可.
1.abstract public String filterType();
返回过滤器的类型
以下提供四种标准的Filter类型及其在请求生命周期中所处的位置:
- PRE Filter:在请求路由到目标之前执行。一般用于请求认证、负载均衡和日志记录。
- ROUTING Filter:处理目标请求。这里使用Apache HttpClient或Netflix Ribbon构造对目标的HTTP请求。
- POST Filter:在目标请求返回后执行。一般会在此步骤添加响应头、收集统计和性能数据等。
- ERRORFilter:整个流程某块出错时执行。
2.abstract public int filterOrder();
作用;设置filter执行顺序,返回int,小值优先执行
Filter请求的生命周期
Zuul自带Filter,在zuul.filter包下
pre过滤器:
1.ServletDetectionFilter
- filterOrder返回-3,总是会执行,判断请求是DispatcherServlet的请求还是ZuulServlet的请求.
- 结果会放在RequestContext中的isDispatcherServletRequest参数中,后面可以通过调用RequestUtils.isDispatcherServletRequest()得到结果.一般情况发送在API外部的请求都是通过DispatcherServletReuqest的,只有从Zuul网关过来的是走ZuulServlet
2.Servlet30WrapperFilter
- filterOrder返回-2,用来将Servlet包装为3.0,Zuul默认Servlet为2.5
3.FormBodyWrapperFilter
- filterOrder返回-1,对Content-Type为application/x-www-form-urlencoded的请求和Content-Type为multipart/form-data并且是由Spring的DispatcherServlet处理的请求(用到了ServletDetectionFilter的处理结果)生效.
- 作用是将符合要求的请求体包装成FormBodyRequestWrapper对象
4.DebugFilter
- filterOrder返回为1,在设置为DEBUG等级的时候执行,在上下文中将debug设为true.
- .由于在同一个请求的不同生命周期中,都可以访问到这两个值,所以我们在后续的各个过滤器中可以利用这两值来定义一些debug信息,这样当线上环境出现问题的时候,可以通过请求参数的方式来激活这些debug信息以帮助分析问题。
- 对于请求参数中的debug参数,我们也可以通过zuul.debug.parameter来进行自定义。
5.PreDecorationFilter
- filterOrder返回为5,是pre中最后一个执行的filter.
- 该过滤器会判断当前请求上下文中是否存在forward.to和serviceId参数,如果都不存在,那么它就会执行具体过滤器的操作(如果有一个存在的话,说明当前请求已经被处理过了,因为这两个信息就是根据当前请求的路由信息加载进来的)。
而它的具体操作内容就是为当前请求做一些预处理,比如:进行路由规则的匹配、在请求上下文中设置该请求的基本信息以及将路由匹配结果等一些设置信息等,这些信息将是后续过滤器进行处理的重要依据,我们可以通过RequestContext.getCurrentContext()来访问这些信息。
另外,我们还可以在该实现中找到一些对HTTP头请求进行处理的逻辑,其中包含了一些耳熟能详的头域,比如:X-Forwarded-Host、X-Forwarded-Port。
另外,对于这些头域的记录是通过zuul.addProxyHeaders参数进行控制的,而这个参数默认值为true,所以Zuul在请求跳转时默认地会为请求增加X-Forwarded-*头域,包括:X-Forwarded-Host、X-Forwarded-Port、X-Forwarded-For、X-Forwarded-Prefix、X-Forwarded- Proto。
我们也可以通过设置zuul.addProxyHeaders=false关闭对这些头域的添加动作。
route过滤器
1.RibbonRoutingFilter
- filterOrder返回10,是route阶段第一个执行的过滤器.只对上下文中有serviceId的请求生效.
- 通过Ribbon和Hystrix向服务实例发起请求,并返回请求结果.
2.SimpleHostRoutingFilter
- filteOrder返回100,route阶段是第二个执行的过滤器.
- 对上下文中有routeHost参数的请求进行处理.即只对通过url配置路由规则的请求生效。而该过滤器的执行逻辑就是直接向routeHost参数的物理地址发起请求,从源码中我们可以知道该请求是直接通过httpclient包实现的,而没有使用Hystrix命令进行包装,所以这类请求并没有线程隔离和断路器的保护
3.SendForwardFilter
- filterOrder返回500,是route阶段最后一个执行的过滤器,
- 对上下文中包含forward.to参数的请求进行过滤.即用来处理路由规则中的forward本地跳转配置
post过滤器
1.SendErrorFilter
- filterOrder返回是0,是post阶段第一个执行的过滤器。
- 该过滤器仅在请求上下文中包含error.status_code参数(由之前执行的过滤器设置的错误编码)并且还没有被该过滤器处理过的时候执行。而该过滤器的具体逻辑就是利用请求上下文中的错误信息来组织成一个forward到API网关/error错误端点的请求来产生错误响应。
2.LocationRewriteFilter
-
filterOrder返回为 (1000 - 100)
-
SEND_RESPONSE_FILTER_ORDER是SendResponseFilter的执行顺序.为Post最后执行的过滤器,此过滤器的作用为结束请求后再次重定向的路径进行标记,为ZuulFilter.
3.SendResponseFilter
- filterOrder是Post阶段最后一个执行的过滤器.
- 返回的response中Header,DataStream或者body任意一个不为空.,则把返回的内容组织处理后返回客户端.
Filter类型
类型 | 顺序 | 类名 | 功能 |
---|---|---|---|
pre | -3 | ServletDetectionFilter | 标记处理Servlet的类型 |
pre | -2 | Servlet30WrapperFilter | 包装HttpServletRequest请求 |
pre | -1 | FormBodyWrapperFilter | 包装请求体 |
route | 1 | DebugFilter | 标记调试标志 |
route | 5 | PreDecorationFilter | 处理请求上下文供后续使用 |
route | 10 | RibbonRoutingFilter | serviceId请求转发 |
route | 100 | SimpleHostRoutingFilter | url请求转发 |
route | 500 | SendForwardFilter | forward请求转发 |
post | 0 | SendErrorFilter | 处理有错误的请求响应 |
post | 1000-100 | LocationRewriteFilter | 处理返回重定向,标记为ZuulFilter |
post | 1000 | SendResponseFilter | 处理正常的请求响应 |
执行过滤器的核心类FilterProcessor
作用:runFilter (String sType); 入参为Filter类型
1. 获取对应类型的Filter并排序返回
2.执行Filter
public Object processZuulFilter(ZuulFilter filter) throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
boolean bDebug = ctx.debugRouting();
final String metricPrefix = "zuul.filter-";
long execTime = 0;
String filterName = "";
try {
long ltime = System.currentTimeMillis();
filterName = filter.getClass().getSimpleName();
RequestContext copy = null;
Object o = null;
Throwable t = null;
if (bDebug) {
Debug.addRoutingDebug("Filter " + filter.filterType() + " " + filter.filterOrder() + " " + filterName);
//copyContext 用于Debug调试
copy = ctx.copy();
}
ZuulFilterResult result = filter.runFilter();
ExecutionStatus s = result.getStatus();
execTime = System.currentTimeMillis() - ltime;
switch (s) {
case FAILED:
t = result.getException();
ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);
break;
case SUCCESS:
o = result.getResult();
ctx.addFilterExecutionSummary(filterName, ExecutionStatus.SUCCESS.name(), execTime);
if (bDebug) {
Debug.addRoutingDebug("Filter {" + filterName + " TYPE:" + filter.filterType() + " ORDER:" + filter.filterOrder() + "} Execution time = " + execTime + "ms");
Debug.compareContextState(filterName, copy);
}
break;
default:
break;
}
if (t != null) throw t;
usageNotifier.notify(filter, s);
return o;
} catch (Throwable e) {
if (bDebug) {
Debug.addRoutingDebug("Running Filter failed " + filterName + " type:" + filter.filterType() + " order:" + filter.filterOrder() + " " + e.getMessage());
}
usageNotifier.notify(filter, ExecutionStatus.FAILED);
if (e instanceof ZuulException) {
throw (ZuulException) e;
} else {
ZuulException ex = new ZuulException(e, "Filter threw Exception", 500, filter.filterType() + ":" + filterName);
ctx.addFilterExecutionSummary(filterName, ExecutionStatus.FAILED.name(), execTime);
throw ex;
}
}
}
执行具体的run
标签:返回,Filter,Zuul,请求,Netflix,filter,源码,过滤器,filterOrder 来源: https://blog.csdn.net/weixin_44065695/article/details/113663821
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。