过滤器是Zuul的核心组件,这篇文章用来记录Zuul的过滤器相关内容。
过滤器类型与请求声明周期
Zuul大部分功能都是通过过滤器来实现的。Zuul中定义了4种标准类型过滤器,这些过滤器正好对应于请求的典型生命周期。
-
PRE
这种过滤器在请求被路由之前调用。可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调式信息等。 -
ROUTING
这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或 Netfilx Ribbon请求微服务。 -
POST
这种过滤器在路由到微服务以后执行。这种过滤器可以用来为响应添加标准的Http Header、收集统计信息和指标、将响应从微服务发送给客户端等。 -
ERROR
在其他阶段发生错误时执行该过滤器。
除了上面默认的过滤器类型外,Zuul还允许创建自定义的过滤器类型。例如,可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端微服务。
Zuul请求的生命周期如下图所示,该图详细描述了各种类型过滤器的执行顺序。
我们来进行编写一个Zuul过滤器
编写一个Zuul的过滤器非常简单,只需要继承抽象类ZuulFilter
,然后实现几个抽象方法就可以了。
接下来,我们编写一个简单的Zuul过滤器,让该过滤器打印请求日志。
- 编写自定义Zuul过滤器
public class PreRequestLogFilter extends ZuulFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(PreRequestLogFilter.class);
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
PreRequestLogFilter.LOGGER.info(String.format("send %s request to %s",request.getMethod(),request.getRequestURL().toString()));
return null;
}
}
由代码可知,自定义的Zuul Filter需要实现下面几个方法。
- filterType: 返回过滤器的类型。有pre、route、post、error等几种取值,分别对应上文的几种过滤器。详情可以参考
com.netfilx.zuul.ZuulFilter.filterType()
中的注释。 - filterOrder: 返回一个int值来指定过滤器的执行顺序,不同的过滤器允许返回相同的数字。
- shouldFilter: 返回一个boolean值来判断该过滤器是否要执行,true表示执行,false表示不执行。
- run: 过滤器的具体逻辑。这里我让它打印了请求的HTTP方法以及请求地址。
- 修改springboot工程的启动类,为启动类添加一下内容:
@Bean
public PreRequestLogFilter preRequestLogFilter() {
return new PreRequestLogFilter();
}
测试:
访问 http://localhost:port/microservice-name/uri
,可以获得类似如下日志:
send GET request to http://localhost:8040/microservice-provider-user/1
禁用Zuul过滤器
Spring Cloud默认为Zuul编写并启用了一些过滤器,例如DebugFilter,FormBodyWrapperFilter、PreDecorationFilter等。这些过滤器都存放在spring-cloud-netfilx-core 这个Jar包的org.springframework.cloud.netflix.zuul.filters
包中。
一些场景下,想要禁用掉部分过滤器,该怎么办?
答案非常简单,只须设置zuul...disable=true,即可禁用SimpleClassName 所对应的过滤器。如果想要禁用掉我们上门所编写的过滤器,只需设置zuul.PreRequestLogFilter.pre.disable=true
即可。