一、Spring Cloud Zuul 过滤链
1.1 工作原理
Zuul的核心逻辑是由一系列的Filter来实现的,他们能够在进行HTTP请求或者相应的时候执行相关操作。Zuul Filter的主要特性有一下几点:
- Filter的类型:Filter的类型决定了它在Filter链中的执行顺序。路由动作发生前、路由动作发生时,路由动作发生后,也可能是路由过程发生异常时。
- Filter的执行顺序:同一种类型的Filter可以通过filterOrder()方法来设定执行顺序
- Filter的执行条件:Filter运行所需要的条件
- Filter的执行效果:符合某个Filter执行条件,产生的执行效果
Zuul内部提供了一个动态读取、编译和运行这些Filter的机制。Filter之间不能直接通信,在请求线程中通过RequestContext来共享状态,它的内部是用ThreadLocal实现的。
上图描述了Zuul关于Filter的请求生命周期。
- pre:在Zuul按照规则路由到下级服务之前执行。如果需要对请求进行预处理,比如鉴权、限流等,可在考虑在这类Filter中实现。
- route:这类Filter是Zuul路由动作的执行者,是Http客户端构建和发送HTTP请求的地方。
- post:这类Filter是在原服务返回结果或者异常信息发生后执行,如果需要对返回信息做一些处理,可以在此类Filter进行处理。
- error:在整个生命周期内如果发生异常,则会进入error Filter,可以做全局异常处理
其中post Filter抛出错误分成两种情况:
1)在post Filter抛错之前,pre、route Filter没有抛错,此时会进入ZuulException的逻辑,打印堆栈信息,然后再返回status=500的Error信息
2)再post Filter跑错之前,pre、route Filter已有跑错,此时不会打印堆栈信息,直接返回status=500的error信息。
也就是说整个责任链中重点不只是post Filter,还可能是error Filter。
在实际项目中,需要子实现以上类型的Filter来对链路进行处理,根据业务的需求,选取对应生命周期的Filter来达到目的。每个Filter之间通过RequestContext(Zuul包中)类来进行通信,内部采用ThreadLocal保存每个请求的一些信息,包括请求路由,错误信息,HttpServletRequest,HttpServletResponse,这使得一些操作十分可靠,它害扩展了ConcurrentHashMap,目的是为了在处理过程中保存任何形式的信息。
1.2 Zuul中的原生Filter
Zuul Server通过@EnableZuulProxy
开启之后,搭配Spring Boot Actuator,会多两个管控断点。
在配置文件中配置一下:
management:
endpoints:
web:
exposure:
include: 'routes,filters'
复制代码
1、/route:返回当前Zuul Server中已生成的映射规则,加上/details可查看明细。例如
每个路由的详细信息
2、/filters:返回当前Zuul Filter中已注册生效的Filter
从Filter的信息可以看到,所有已经注册生效的Filter的信息:Filter实现类的路径、Filter执行次序、是否被禁用、是否静态。而且很明显地可以看出Zuul内Filter的整个请求的生命流程,如下图:
Zuul中各内置的Filter:
名称 | 类型 | 次序 | 描述 |
---|---|---|---|
ServletDetectionFilter | pre | -3 | 通过Spring Dispatcher检查请求是否通过 |
Servlet30WrapperFilter | pre | -2 | 适配HttpServletRequest为Servlet30RequestWrapper对象 |
FormBodyWrapperFilter | pre | -1 | 解析表单数据并为下游请求重新编码 |
DebugFiter | pre | 1 | Debug路由表示 |
PreDecorationFilter | pre | 5 | 处理请求上下文共后续使用,设置下游相关信息头 |
RibbonRoutingFilter | route | 10 | 使用Ribbon、Hystrix或者嵌入式HTTP客户端发送请求 |
SimpleHostRoutingFilter | route | 100 | 使用Apache Httpclient转发请求 |
SendForwardFilter | route | 500 | 使用Servlet转发请求 |
SendResponseFilter | post | 1000 | 将代理请求的响应写入当前相应 |
SendErrorFilter | error | 0 | 如果RequestContext.getThrowable()不为空,则转发到error.path配置的路径 |
上表为使用@EnableZuulProxy
之后安装的Filter,当使用@EnableZuulServer
将会缺少PreDecorationFilter、RibbonRoutingFilter、SimpleHostRoutingFilter。这些原生的Filter可以关掉,例如:在配置文件里面配置zuul.SendErrorFilter.error.disable=true
1.3 多过滤器组成过滤链
在实际中我们不仅是只定义一个过滤器,而是多个过滤器组成过滤链来完成工作,除了Zuul的其他网关也是有这个功能
要在Zuul中自定义Filter子需要继承ZuulFilter即可。它是个抽象类,主要实现的几个方法:
String filterType()
:使用返回值定义Filter的类型,有pre、route、post、errorint filterOrder()
:使用返回值设置Filter的执行顺序boolean shouldFilter()
:使用返回值设置Filter是否执行,