九、微服务网关之Zuul过滤器


过滤器类型与请求生命周期

  • PRE:这种过滤器在请求被路由之前调用。可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
  • ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClientNetfilx Ribbon请求微服务。
  • POST:这种过滤器在路由到微服务后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
  • ERROR:在其他阶段发生错误时执行该过滤器。

除了默认的过滤器类型,Zuul还允许创建自定义的过滤器类型。例如,可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。

过滤器


内置过滤器详解

@EnableZuulProxy是最常用的注解,是@EnableZuulServer的增强版。

RequestContext扩展了ConcurrentHashMap,用于在过滤器之间传递消息。它的数据保存在每个请求的ThreadLocal中。用于存储请求路由到哪里、错误、HttpServletHttpServletResponse等信息。

@EnableZuulServer所启用的过滤器
  • pre 类型过滤器
  1. ServletDetectionFilter:该过滤器用于检查请求是否通过Spring Dispatcher。检查后,通过FilterConstants.IS_DISPATCHER_SERVLET_REQUEST_KEY(isDispatcherServletRequest)设置布尔值。
  2. FormBodyWrapperFilter:解析表单数据,并为请求重新编码。
  3. DebugFilter:顾名思义,调试用的过滤器,当设置zuul.include-debug-header=truezuul.debug.request=true ,并在请求时,加上debug=true的参数,例如$ZUUL_HOST:ZUUL_PORT/path?debug=true,就会开启该过滤器。该过滤器就会把RequestContext.setDebugRouting()RequestContext.setDebugRequest()设为 true。
  • route 类型过滤器

SendForwardFilter:该过滤器使用Servlet RequestDispatcher转发请求,转发位置存储在RequestContext的属性FilterConstants.FOREWARD_TO_KEY 中。这对转发到Zuul自身的端点很有用。可以将路由改成:

zuul:
  routes:
    abc:
      path: /path-a/**
      url: forward:/path-b

然后访问$ZUUL_HOST:ZUUL_PORT/path-a ,观察该过滤器的执行过程。

  • post 类型过滤器

SendResponseFilter:将Zuul所代理请求的的响应写入当前响应。

  • error 类型过滤器

SendErrorFilter:如果RequestContext.getThrowable() 不为 null,那么默认就会转发到/error,也可以设置error.path属性修改默认的转发路径。

@EnableZuulProxy所启用的过滤器

如果使用注解@EnableZuulProxy,那么除上述过滤器之外,Spring Cloud还会安装以下过滤器:

  • pre 类型过滤器

PreDecorationFilter:该过滤器根据提供的RouteLocator确定路由到的地址,以及怎样去路由。该路由器也可为后端请求设置各种代理相关的 header。

  • route 类型过滤器
  1. RibbonRoutingFilter:该过滤器使用RibbonHystrix和可插拔的 HTTP 客户端发送请求。serviceId 在RequestContext的属性FilterConstants.SERVICE_ID_KEY(RequestContext.getCurrentContext().get("serviceId")) 中。该过滤器可使用不同的 HTTP 客户端。
  • Apache HttpClient:默认的 HTTP 客户端。
  • Squareup OkHttpClient v3:如需使用该客户端,需保证com.squareup.okhttp3的依赖在 classpath 中,并设置ribbon.okhttp.enabled = true
  • Netflix Ribbon HTTP client:设置ribbon.restclient.enabled = true 即可启用该 HTTP 客户端。需要注意的是,该客户端有一定限制,例如不支持 PATCH 方法,另外,它有内置的重试机制。
  1. SimpleHostRoutingFilter:该过滤器通过Apache HttpClient向指定的 URL 发送请求。URL 在RequestContext.getRouteHost()中。

编写Zuul过滤器

  1. 编写自定义Zuul过滤器:
public class PreRequestLogFilter extends ZuulFilter {

    private static final Logger LOGGER = LoggerFactory.getLogger(PreRequestLogFilter.class);

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

    @Override
    public int filterOrder() {
        return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        PreRequestLogFilter.LOGGER.info((String.format("send %s request to %s", request.getMethod(), request.getRequestURI())));
        return null;
    }
}

由代码可知,自定义的 Zuul Filter 需实现以下几个方法:

  • filterType:返回过滤器的类型。有prerouteposterror等几种取值,分别对应上文的几种过滤器。详细可以参考com.netflix.zuul.ZuulFilter.filterType() 中的注释。
  • filterOrder:返回一个 int 值来指定过滤器的执行顺序,不同的过滤器允许返回相同的数字。
  • shouldFilter:返回一个 boolean 值来判断该过滤器是否要执行,true 表示执行,false 表示不执行。
  • run:过滤器的具体逻辑。本例中,我们让它打印了请求的 HTTP 方法以及请求的地址。
  1. 在启动类上添加:
@Bean
public PreRequestLogFilter preRequestLogFilter() {
    return new PreRequestLogFilter();
}
  1. 启动用户微服务,
    访问http://127.0.0.1:8040/microservice-provider-user/1,获得如下日志:
INFO 9107 --- [nio-8040-exec-3] c.i.z.m.PreRequestLogFilter              : send GET request to /microservice-provider-user/1

说明自定义Zuul过滤器被执行了。

禁用Zuul过滤器

Spring Cloud默认为Zuul编写并启用了一些过滤器,例如DebugFilterFormBodyWrapperFilterPreDecorationFilter等。这些过滤器都存放在spring-cloud-netflix-core这个 Jar 包的org.springframework.cloud.netflix.zuul.filters包中。

一些场景下,我们想要禁用掉部分过滤器,只需设置zuul...disable=true ,即可禁用SimpleClassName所对应的过滤器。以过滤器org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter为例,只需设置zuul.SendResponseFilter.post.disable=true ,即可禁用该过滤器。


该文章摘自《Spring Cloud 与 Docker 微服务架构实战(第二版)》

以上


文章作者: Qliang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Qliang !
评论
 上一篇
十、微服务网关之Zuul容错与回退 十、微服务网关之Zuul容错与回退
Spring Cloud中,Zuul默认已经整合了Hystrix。 Zuul回退编写Zuul回退类: @Component public class MyFallbackProvider implements FallbackProvide
2019-01-26
下一篇 
八、微服务网关之Zuul 八、微服务网关之Zuul
为什么要用微服务网关如下图,外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与微服务通信会产生以下的问题: 客户端会多次请求不同的微服务,增加了客户端的复杂性。 存在跨域请求,在一定场景下处理比较复杂。 认证复杂
2019-01-24
  目录