过滤器是Zuul功能的核心部分。它们负责应用的业务逻辑以及执行多种任务。
- Type:当Filter被使用时,该值多数情况下是定义在路由执行时的阶段(尽管可以是用户定义的字符串)
- Async:定义Filter是同步还是异步执行,通常意思是你需要另外的调用或者是仅仅是在容器上运行
- Execution Order:应用于Type内部,定义多个过滤器的执行顺序
- Criteria:过滤器被执行所需要的条件
-
Action:Criteria被匹配到时执行的操作
Zuul提供了一个框架,可以动态的读取、编译、和运行这些过滤器。过滤器之间不能直接通信,而是通过RequestContext来共享状态信息,每个请求的RequestContext是唯一的。在Zuul1中就是RequestContext类,在Zuul2中改为了SessionContext类。
过滤器目前是通过Groovy写的,其实Zuul支持任何基于JVM的语言。每个过滤器的源代码被写入到Zuul服务其的特定目录下并且定期拉取变化。更新过的过滤器会从硬盘读取,动态编译到正在运行的服务器中,并且会被接下来的请求通过Zuul来调用。
Incoming
Incoming Filters在请求被代理到原始处理类之前执行。通常大多数业务逻辑在这里执行。例如授权、动态路由、限流、DDos保护,度量。
Endpoint
Endpoint Filters负责处理incoming filters执行之后的请求。Zuul自带了内置构建的过滤器(ProxyEndpoint)来代理请求到后端服务器,所以这类过滤器典型的使用场景就是静态endpoints。例如健康检测响应,静态错误响应,404响应。
Outgoing
Outgoing Filters是接收到后端服务器的响应后进行处理。典型地,该类过滤器更多的用来塑造响应,增加度量。例如保存统计,增加/移除标准头(headers),发送时间到实时流,压缩响应。
Async
过滤器可以通过同步或者异步的方式执行。如果定义的过滤器不会做大量的工作并且没有阻塞或者关闭,则可以通过继承HttpInboundSyncFilter或者HttpOutboundSyncFilter来安全的使用同步顾虑器。
然而,在某些场景下,如果需要从其他服务或者缓存中获取数据或者做大量的计算工作。这种情况下,就不应该阻塞Netty线程,所以应该使用异步的过滤器返回可监视的响应包装。这类的过滤器应该继承HttpInboundFilter或者HttpOutboundFilter。
如:同步过滤器
class Routes extends HttpInboundSyncFilter {
@Override
int filterOrder() {
return 0
}
@Override
boolean shouldFilter(HttpRequestMessage httpRequestMessage) {
return true
}
@Override
HttpRequestMessage apply(HttpRequestMessage request) {
SessionContext context = request.getContext()
String path = request.getPath()
String host = request.getOriginalHost()
// Route healthchecks to the healthcheck endpoint.;
if (path.equalsIgnoreCase("/healthcheck")) {
context.setEndpoint(Healthcheck.class.getCanonicalName())
}
else {
context.setEndpoint(ZuulEndPointRunner.PROXY_ENDPOINT_FILTER_NAME);
context.setRouteVIP("api")
}
return request
}
}
异步过滤器:
class SampleServiceFilter extends HttpInboundFilter {
private static final Logger log = LoggerFactory.getLogger(SampleServiceFilter.class)
private final SampleService sampleService
@Inject
SampleServiceFilter(SampleService sampleService) {
this.sampleService = sampleService
}
@Override
int filterOrder() {
return 500
}
@Override
boolean shouldFilter(HttpRequestMessage msg) {
return sampleService.isHealthy()
}
@Override
Observable<HttpRequestMessage> applyAsync(HttpRequestMessage request) {
return sampleService.makeSlowRequest().map({ response ->
log.info("Fetched sample service result: {}", response)
return request
})
}
获取请求体内容
默认情况下Zuul是不缓存请求体内容(body content)的,也就是Zuul接受请求体之前就会将接收到的头信息(headers)流向原始处理类。这里说的流向的行为是非常高效的和有必要的,只要你的过滤器逻辑依赖于头数据(header data)。但是,如果你希望在inbound过滤器中拿到请求体或者在outbound过滤器中拿到响应体内容,则需要明确的告诉Zuul来缓冲内容体(body)。可以在过滤器中通过覆盖needsBodyBuffered()
方法来实现:
@Override
boolean needsBodyBuffered(HttpResponseMessage input) {
return true
}
有用的过滤器
Zuul自带了一些有用的过滤器。
示例过滤器
- DebugRequest - 查询请求参数来为一个请求增加额外的调试日志
- Healthcheck - 简单的静态endpoint过滤器,如果应用可以被正确引导启动,就只是返回200
- ZuulResponseFilter - 增加请求头信息来提供额外的细节给路由、请你去执行、状态或者错误原因
核心过滤器
- GZipResponseFilter - 开启后来压缩outbound的响应
- SurgicalDebugFilter - 开启后路由指定的请求到不同的主机上以便进行调试
网友评论