接上篇《​​27.通过Zuul上传文件​​》  Spring Cloud版本为Finchley.SR2版

上一篇我们介绍了使用Zuul上传文件的相关知识。本篇我们来介绍有关Zuul的Filter过滤器禁用和Zuul回退的相关知识。
本部分官方文档:​​​https://cloud.spring.io/spring-cloud-static/Finchley.SR4/single/spring-cloud.html#_disable_zuul_filters​​ 注:好像Finchley.SR2的文档已经挂了,最新的是Finchley.SR4的文档。

一、Zuul的Filter过滤器

Zuul的大部分功能都是基于Filter过滤器的,这个Filter不是我们Web开发中Servlet的Filter,而是Zuul自己的Filter,但其功能类似于Servlet框架的Filter以及AOP功能。

Spring Cloud中默认已经为Zuul编写并启用了一些过滤器,这些过滤器都在spring-cloud-netflix-zuul这个Jar包的org.springframework.cloud.netflix.zuul.filters包中,我们可以打开编译器看一下:

【Spring Cloud总结】28.Zuul的Filter过滤器_spring cloud


可以看到,filters过滤器包下面有很多种类的过滤器,例如“discovery”包下的服务发现相关过滤器,“pre”包下的前置过滤器,“route”包下的路由过滤器。

我们打开pre包,可以看到下面有“DebugFilter”、“FormBodyWrapperFilter”、“PreDecorationFilter”等过滤器:

【Spring Cloud总结】28.Zuul的Filter过滤器_spring cloud_02


我们点开“DebugFilter”可以看到,该过滤器继承了ZuulFilter父类:

package org.springframework.cloud.netflix.zuul.filters.pre;

import javax.servlet.http.HttpServletRequest;
import com.netflix.config.DynamicBooleanProperty;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.constants.ZuulConstants;
import com.netflix.zuul.context.RequestContext;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.DEBUG_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

/**
* Pre {@link ZuulFilter} that sets {@link RequestContext} debug attributes to true if
* the "debug" request parameter is set.
* @author Spencer Gibb
*/
public class DebugFilter extends ZuulFilter {

private static final DynamicBooleanProperty ROUTING_DEBUG = DynamicPropertyFactory
.getInstance().getBooleanProperty(ZuulConstants.ZUUL_DEBUG_REQUEST, false);
private static final DynamicStringProperty DEBUG_PARAMETER = DynamicPropertyFactory
.getInstance().getStringProperty(ZuulConstants.ZUUL_DEBUG_PARAMETER, "debug");

@Override
public String filterType() {
return PRE_TYPE;
}

@Override
public int filterOrder() {
return DEBUG_FILTER_ORDER;
}

@Override
public boolean shouldFilter() {
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
if ("true".equals(request.getParameter(DEBUG_PARAMETER.get()))) {
return true;
}
return ROUTING_DEBUG.get();
}

@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
ctx.setDebugRouting(true);
ctx.setDebugRequest(true);
return null;
}
}

打开其他的过滤器也是如此,也就是说,需要实现Zuul的过滤器,就需要继承ZuulFilter的父类,通过上面的过滤器例子,可以知道继承ZuulFilter父类后,要实现filterType()、filterOrder()、shouldFilter()以及run()方法,其中:
(1)filterType()方法为获取该过滤器的类型。
通过“FilterConstants”类中的Type常量,我们可以知晓,Zuul的标准过滤器一共有“error”、“post”、“pre”和“route”的类型:

// Zuul Filter TYPE constants -----------------------------------

/**
* {@link ZuulFilter#filterType()} error type.
*/
public static final String ERROR_TYPE = "error";

/**
* {@link ZuulFilter#filterType()} post type.
*/
public static final String POST_TYPE = "post";

/**
* {@link ZuulFilter#filterType()} pre type.
*/
public static final String PRE_TYPE = "pre";

/**
* {@link ZuulFilter#filterType()} route type.
*/
public static final String ROUTE_TYPE = "route";

其中:
PRE:这种过滤器在请求被路由之前调用。可利用这种过滤器实现身份验证、在集群中选择请求的微服务,记录调试信息等。
ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache?HttpClient或Netflix?Ribbon请求微服务。
POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP header、收集统计信息和指标、将响应从微服务发送给客户端等。
ERROR:在其他阶段发送错误时执行该过滤器。
除了上面的标准过滤器以外,Zuul还允许我们自定义过滤器类型。比如我们可以自定义一个STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。
Zuul请求的生命周期如下图:

【Spring Cloud总结】28.Zuul的Filter过滤器_zuul过滤器_03

该图详细描述了各种类型的过滤器的执行顺序。

(2)filterOrder()方法为获取过滤器在责任链中的顺序,其中数值越大,越后执行;
这里各个filter之间不直接进行交互,而是通过RequestContext来共享状态信息。
(3)shouldFilter()方法获取是否需要执行该过滤;
(4)run()方法就是该过滤器的具体过滤逻辑的执行。

上面的DebugFilter就是来设置RequestContext上下文对象的请求和路由是否进行Debug的设置。
如果我们要自定义Zuul的Filter过滤器,继承ZuulFilter父类,并实现以上四个方法即可。Zuul会动态的读取,编译,运行新添加的filter,

二、编写Zuul的自定义过滤器

这里我们来编写一个过滤器,并禁用它试一下。
首选我们在之前的“microserver-getaway-zuul”工程下的“”包下,新建一个“RiskCheckFilter”类,并继承自ZuulFilter父类:

package com.microserver.cloud;

import javax.servlet.http.HttpServletRequest;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.util.StringUtils;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;

public class RiskCheckFilter extends ZuulFilter{

@Override
public boolean shouldFilter() {
return true;//执行该过滤器
}

@Override
public Object run() throws ZuulException {
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
String URI = request.getRequestURI();
if(URI.contains("/findById/")) {
//获取RESTful风格请求URI"/user/findById/1" 中的“1"
String userId = URI.split("/")[3];
if(!StringUtils.isEmpty(userId)&&userId.equals("1")) {
System.out.println("请求了UserId为1的用户,有风险!!!");
}else {
System.out.println("请求了UserId不为1的用户,无风险~~");
}
}
return null;
}

@Override
public String filterType() {
return FilterConstants.PRE_TYPE;//类型为pre
}

@Override
public int filterOrder() {
return 1;//过滤器排序为1号
}
}

该类完成的功能是,在用户访问微服务中,如果userId为1的话,认为是有风险的,会提示风险信息。这里我们的filterType()为“pre”,意味着让该过滤器在请求被路由之前调用。然后把RiskCheckFilter类在启动类“MircoserverGateWayZuulApplication”中注入Bean对象:

package com.microserver.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableZuulProxy
public class MircoserverGateWayZuulApplication {

@Bean
public RiskCheckFilter riskCheckFilter() {
return new RiskCheckFilter();
}

public static void main(String[] args) {
SpringApplication.run(MircoserverGateWayZuulApplication.class, args);
}
}

此时启动我们的Zuul微服务、user微服务以及eureka微服务:

【Spring Cloud总结】28.Zuul的Filter过滤器_ZuulFilter_04


然后在eureka Server注册中心确认两个微服务都成功启动:

【Spring Cloud总结】28.Zuul的Filter过滤器_禁用过滤器_05


然后通过Zuul去访问user的服务,设置Id为1,可以看到控制台的打印:

【Spring Cloud总结】28.Zuul的Filter过滤器_spring cloud_06

【Spring Cloud总结】28.Zuul的Filter过滤器_zuul过滤器_07


然后我们再请求一个Id为2的user信息,控制台打印:

【Spring Cloud总结】28.Zuul的Filter过滤器_zuul过滤器_08


这里证明我们的过滤器设置成功!

三、禁用Zuul的Filter过滤器

在某些情况下,我们需要对Zuul的某些过滤器进行禁用,我们只需要在配置文件中,通过以下格式来禁用某个过滤器即可:
zuul.<SimpleClassName>.<filterType>.disable=true
例如禁用 org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter 过滤器,我们设置为zuul.SendResponseFilter.post.disable=true即可。

参考:《51CTO学院Spring Cloud高级视频》