Zuul给我们的第一印象凡是是这样:它包罗了对请求的路由和过滤两个成果,此中路由成果卖力将外部请求转发到具体的微处事实例上,是实现外部访谒统一入口的根本。过滤器成果则卖力对请求的措置惩罚惩罚过程进行干与干预,是实现请求校验、处事聚合等成果的根本。然而实际上,路由成果在真正运行时,它的路由映射和请求转发都是由几个差此外过滤器完成的。此中,路由映射主要是通过PRE类型的过滤器完成,它将请求路径与配置的路由法则进行匹配,以找到需要转发的方针地点。而请求转发的部分则是由Route类型的过滤器来完成,对PRE类型过滤器获得的路由地点进行转发。所以,过滤器可以说是Zuul实现API网关成果最重要的核心部件,每一个进入Zuul的请求城市颠末一系列的过滤器措置惩罚惩罚链得到请求响应并返回给客户端。
1. 过滤器简介 1.1 过滤器特性Zuul过滤器的关键特性有:
Type: 界说在请求执行过程中何时被执行;
Execution Order: 当存在多个过滤器时,用来指示执行的挨次,值越小就会越早执行;
Criteria: 执行的条件,即该过滤器何时会被触发;
Action: 具体的行动。
过滤器之间并不会直接进行通信,而是通过RequestContext来共享信息,RequestContext是线程安适的。
对应上面Zuul过滤器的特性,我们在实现一个自界说过滤器时需要实现的要领有:
/** * Zuul Pre-Type Filter * * @author CD826([email protected]) * @since 1.0.0 */ public class PreTypeZuulFilter extends ZuulFilter { protected Logger logger = LoggerFactory.getLogger(PreTypeZuulFilter.class); @Override public String filterType() { return PRE_TYPE; } @Override public int filterOrder() { return PRE_DECORATION_FILTER_ORDER - 1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { this.logger.info("This is pre-type zuul filter."); return null; } }
此中:
filterType()要领是该过滤器的类型;
filterOrder()要领返回的是执行挨次;
shouldFilter()要领例是判断是否需要执行该过滤器;
run()则是所要执行的具体过滤行动。
1.2 过滤器类型Zuul中界说了四种标准的过滤器类型,这些过滤器类型对应于请求的范例生命周期。
PRE过滤器: 在请求被路由之前挪用, 可用来实现身份验证、在集群中选择请求的微处事、记录调试信息等;
ROUTING过滤器: 在路由请求时候被挪用;
POST过滤器: 在路由到微处事以后执行, 可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微处事发送给客户端等;
ERROR过滤器: 在措置惩罚惩罚请求过程时产生错误时被挪用。
Zuul过滤器的类型其实也是Zuul过滤器的生命周期,通过下面这张图来了解它们的执行过程。
Zuul-Filter-010
除了上面给出的四种默认的过滤器类型之外,Zuul还允许我们创建自界说的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后真个微处事。
1.3 自界说过滤器示例代码笔者本身没有单独构建一个过滤器示例的场景,我们看一下官方给出的几个示例。
PRE类型示例public class QueryParamPreFilter extends ZuulFilter { @Override public int filterOrder() { return PRE_DECORATION_FILTER_ORDER - 1; // run before PreDecoration } @Override public String filterType() { return PRE_TYPE; } @Override public boolean shouldFilter() { RequestContext ctx = RequestContext.getCurrentContext(); return !ctx.containsKey(FORWARD_TO_KEY) // a filter has already forwarded && !ctx.containsKey(SERVICE_ID_KEY); // a filter has already determined serviceId } @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); if (request.getParameter("foo") != null) { // put the serviceId in `RequestContext` ctx.put(SERVICE_ID_KEY, request.getParameter("foo")); } return null; } }