Spring Cloud之Zuul(五):Zuul的过滤器

版权声明:本文为博主原创文章,可自由转载、引用,但需注明文章出处。 https://blog.csdn.net/StarskyBoy/article/details/85012356

主题

Zuul的过滤器

前言

过滤器是Zuul的核心组件,本博客主要详细讨论一下Zuul的过滤器。

主要包括如下内容:

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

  2. 内置过滤器详解

  • 2.1@EnableZuulServer所启用的过滤器

  • 2.2@EnableZuulProxy所启用的过滤器

  • 2.3编写Zuul过滤器

内容

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

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

Zuul大部分功能都是过滤器实现的。Zuul定义了4种标准的过滤器,分别对应不同的请求的生命周期。

  • PRE:这种过滤器在请求被路由之前调用。可利用这种过滤器实现身份验证、在集群中选择请求的微服务,记录调试信息等。

  • ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netflix Ribbon请求微服务。

  • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP header、收集统计信息和指标、将响应从微服务发送给客户端等。

  • ERROR:在其他阶段发送错误时执行该过滤器。

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

Zuul请求的生命周期如下图,该图详细描述了各种类型的过滤器的执行顺序。

★2.内置过滤器详解★

Spring Cloud默认为Zuul编写并启用了一些过滤器,这些过滤器有什么作用呢?我们不妨按照@EnableZuulServer、@EnableZuulProxy两个注解进行展开,相信大家对这两个注解都不陌生(至少都见过吧)。如果觉得陌生也没有关系,可将@EnableZuulProxy简单理解为@EnableZuulServer的增强版。事实上,当Zuul与Eureka、Ribbon等组件配合使用时,@EnableZuulProxy是我们常用的注解。

在Spring Cloud的官方文档中,只说@EnableZuulServer是一个“空白”的Zuul,那么究竟空白在什么地方呢?与@EnableZuulProxy到底有什么区别呢?诸多问题,都将在本文找到答案。

在此之前,我们先理解什么是RequestContext:

RequestContext:用于在过滤器之间传递消息。它的数据保存在每个请求的ThreadLocal中。它用于存储请求路由到哪里、错误、HttpServletRequest、HttpServletResponse都存储在RequestContext中。RequestContext扩展了ConcurrentHashMap,所以,任何数据都可以存储在上下文(RequestContext)中。

2.1@EnableZuulServer所启用的过滤器

1.pre类型过滤器

(1) ServletDetectionFilter:该过滤器用于检查请求是否通过Spring Dispatcher。检查后,通过FilterConstants.IS_DISPATCHER_SERVLET_REQUEST_KEY设置布尔值。

(2) FormBodyWrapperFilter:解析表单数据,并为请求重新编码。

(3) DebugFilter:顾名思义,调试用的过滤器。可设置zuul.include-debug-header=true或者设置zuul.debug.request=true,并在请求时,加上debug=true的参数,例如$ZUUL_HOST:ZUUL_PORT/path?debug=true开启该过滤器。这样,该过滤器就会把RequestContext.setDebugRouting()以及RequestContext.setDebugRequest()设为true。

2.route类型过滤器

SendForwardFilter:该过滤器使用Servlet RequestDispatcher转发请求,转发位置存储在RequestContext的属性FilterConstants.FORWARD_TO_KEY中。可以将路由设置成:

zuul: 
  routes: 
    abc:  
      path: /abc/** 
      url: forward:/abc 

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

3.post类型过滤器

SendResponseFilter:将Zuul所代理的微服务的响应写入当前响应。

4.error类型过滤器

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

2.2@EnableZuulProxy所启用的过滤器

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

1.pre类型过滤器

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

2.2.route类型过滤器

(1) RibbonRoutingFilter:该过滤器使用Ribbon,Hystrix和可插拔的HTTP客户端发送请求。serviceId在FilterConstants.SERVICE_TO_KEY中。该过滤器可使用不同的HTTP客户端,例如

Apache HttpClient:默认的HTTP客户端

SquareupOkHttpClient v3:如需使用该客户端,需保证com.squareup.okhttp3的依赖在classpath中,并设置ribbon.okhttp.enabled = true。

Netflix Ribbon HTTP client:设置ribbon.restclient.enabled = true即可启用该HTTP客户端。需要注意的是,该客户端有一定限制,例如不支持PATCH方法,另外,它有内置的重试机制。

(2) SimpleHostRoutingFilter:该过滤器通过Apache HttpClient向指定的URL发送请求。URL在RequestContext.getRouteHost()中。

*建议大家看一下源码,特别是RibbonRoutingFilter过滤器源码。

*形如如下内容路由不经过RibbonRoutingFilter,而是走SimpleHostRoutingFilter过滤器。

zuul:
  routes:
    user-route:
      url:http://127.0.0.1:8080/
      path:/user/**

*大家可以通过/filters端点查看过滤器详情

*目前FormBodyWrapperFilter的代码实现并不是很高效,若你没有表单提交,可禁用,从而获得更好的性能表现。

2.3编写Zuul过滤器

编写过滤器很简单,只需继承抽象类ZuulFilter即可。

2.3.1创建项目

复制cloud-register-gateway-zuul微服务修改为cloud-register-gateway-zuul-filter微服务

2.3.2编写自定义Zuul过滤器

public class PreRequestLogFilter extends ZuulFilter {

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

   @Override
   public String filterType() {
       //"pre"类型过滤器
       return FilterConstants.PRE_TYPE;
   }

   @Override
   public int filterOrder() {
       //在PreDecorationFilter之前执行
       return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;
   }

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

   @Override
   public Object run() {
       RequestContext ctx = RequestContext.getCurrentContext();
       HttpServletRequest request = ctx.getRequest();
       logger.info("send {} requtest to {}", request.getMethod(), request.getRequestURI().toString());
       return null;
   }

zuul实现filter的方法:

  • filterType:返回过滤器的类型:pre、route、post、error,分别对应上文的几种过滤器。详情可参考com.netflix.zuul.ZuulFilter.filterType()中的注释。

  • filterOrder:返回int值,来确定filter的执行顺序,不同的过滤器允许返回相同的数字。

  • shouldFilter:返回boolean确定filter是否执行。

  • run:过滤器执行内容。

2.3.3修改启动类,为启动类添加以下内容。

@Bean
public PreRequestLogFilter preRequestLogFilter()
{
  return new PreRequestLogFilter();
}

2.3.4测试

启动cloud-discovery-eureka,port=8001

启动cloud-register-user,port=8002

启动loud-register-file-upload-filter,port=8025

2.3.4结果

出现如下日志,说明ok了

本博客只是简单的demo,过滤器还可以做安全认证、灰度发布、限流等功能。

参考链接:

http://www.fmi.com.cn/index.php?m=content&c=index&a=show&catid=9&id=618616

http://cloud.51cto.com/art/201704/536854.htm

http://www.itmuch.com/spring-cloud-sum/spring-cloud-ratelimit/

源码获取

1.gitee: https://gitee.com/StarskyBoy/cloud

2.github: https://github.com/StarskyBoy/cloud

获取更多信息,请扫我

猜你喜欢

转载自blog.csdn.net/StarskyBoy/article/details/85012356
今日推荐