上篇文章中我们了解了 Spring Cloud Zuul 作为网关所具备的最基本功能:路由(Router),下面我们将关注 Spring Cloud Zuul 的另一核心功能:过滤器(Filter)。

Filter 的作用

我们已经能够实现请求的路由功能,所以我们的微服务应用提供的接口就可以通过统一的 API 网关入口被客户端访问到了。
但是,每个客户端用户请求微服务应用提供的接口时,它们的访问权限往往都需要有一定的限制,系统并不会将所有的微服务接口都对它们开放。然而,目前的服务路由并没有限制权限这样的功能,所有请求都会被毫无保留地转发到具体的应用并返回结果。
为了实现对客户端请求的安全校验和权限控制,最简单和粗暴的方法就是为每个微服务应用都实现一套用于校验签名和鉴别权限的过滤器或拦截器。不过,这样的做法并不可取,它会增加日后的系统维护难度,因为同一个系统中的各种校验逻辑很多情况下都是大致相同或类似的,这样的实现方式会使得相似的校验逻辑代码被分散到了各个微服务中去,冗余代码的出现是我们不希望看到的。所以,比较好的做法是将这些校验逻辑剥离出去,构建出一个独立的鉴权服务。在完成了剥离之后,有不少开发者会直接在微服务应用中通过调用鉴权服务来实现校验,但是这样的做法仅仅只是解决了鉴权逻辑的分离,并没有在本质上将这部分不属于业余的逻辑拆分出原有的微服务应用,冗余的拦截器或过滤器依然会存在。

对于这样的问题,更好的做法是通过前置的网关服务来完成这些非业务性质的校验。由于网关服务的加入,外部客户端访问我们的系统已经有了统一入口,既然这些校验与具体业务无关,那何不在请求到达的时候就完成校验和过滤,而不是转发后再过滤而导致更长的请求延迟。同时,通过在网关中完成校验和过滤,微服务应用端就可以去除各种复杂的过滤器和拦截器了,这使得微服务应用的接口开发和测试复杂度也得到了相应的降低。

Filter 的生命周期

Filter 的生命周期有 4 个,分别是 “PRE”、“ROUTING”、“POST” 和“ERROR”,整个生命周期可以用下图来表示

Zuul 大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命周期。

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

Zuul 中默认实现的 Filter

类型 顺序 过滤器 功能
pre -3 ServletDetectionFilter 标记处理 Servlet 的类型
pre -2 Servlet30WrapperFilter 包装 HttpServletRequest 请求
pre -1 FormBodyWrapperFilter 包装请求体
route 1 DebugFilter 标记调试标志
route 5 PreDecorationFilter 处理请求上下文供后续使用
route 10 RibbonRoutingFilter serviceId 请求转发
route 100 SimpleHostRoutingFilter url 请求转发
route 500 SendForwardFilter forward 请求转发
post 0 SendErrorFilter 处理有错误的请求响应
post 1000 SendResponseFilter 处理正常的请求响应

如何禁用指定的 Filter

可以在 application.yml 中配置需要禁用的 filter,格式为zuul.<SimpleClassName>.<filterType>.disable=true
比如要禁用org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter就设置

zuul:
SendResponseFilter:
post:
disable: true

自定义 Filter

首先自定义一个 Filter,继承 ZuulFilter 抽象类,在 run() 方法中添加具体业务逻辑,具体如下:

 package com.carry.springcloud;

 import javax.servlet.http.HttpServletRequest;

 import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext; public class MyFilter extends ZuulFilter { /**
* 过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。 这里定义为pre,代表会在请求被路由之前执行。
*
* @return
*/
@Override
public String filterType() {
return "pre";
} /**
* filter执行顺序,通过数字指定。 数字越大,优先级越低。
*
* @return
*/
@Override
public int filterOrder() {
return 0;
} /**
* 判断该过滤器是否需要被执行。这里我们直接返回了true,因此该过滤器对所有请求都会生效。 实际运用中我们可以利用该函数来指定过滤器的有效范围。
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
} /**
* 过滤器的具体逻辑
*
* @return
*/
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest(); String token = request.getParameter("token");
if (token == null || token.isEmpty()) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
ctx.setResponseBody("token is empty");
}
return null;
}
}

在上面实现的过滤器代码中,我们通过继承ZuulFilter抽象类并重写了下面的四个方法来实现自定义的过滤器。这四个方法分别定义了:

  • filterType():过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。这里定义为pre,代表会在请求被路由之前执行。
  • filterOrder():过滤器的执行顺序。当请求在一个阶段中存在多个过滤器时,需要根据该方法返回的值来依次执行。通过数字指定,数字越大,优先级越低。
  • shouldFilter():判断该过滤器是否需要被执行。这里我们直接返回了true,因此该过滤器对所有请求都会生效。实际运用中我们可以利用该函数来指定过滤器的有效范围。
  • run():过滤器的具体逻辑。这里我们通过ctx.setSendZuulResponse(false)令 Zuul 过滤该请求,不对其进行路由,然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码,当然我们也可以进一步优化我们的返回,比如,通过ctx.setResponseBody(body)对返回 body 内容进行编辑等。

在实现了自定义过滤器之后,它并不会直接生效,我们还需要为其创建具体的 Bean 才能启动该过滤器,比如,在应用主类中增加如下内容:

 package com.carry.springcloud;

 import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean; @EnableZuulProxy
@SpringBootApplication
public class ServiceApiGatewayApplication { public static void main(String[] args) {
SpringApplication.run(ServiceApiGatewayApplication.class, args);
} @Bean
public MyFilter myFilter() {
return new MyFilter();
}
}

重新启动service-api-gateway,并发起下面的请求,对上面定义的过滤器做一个验证:

Spring Cloud学习笔记【八】服务网关 Zuul(过滤器)的更多相关文章

  1. Spring Cloud(七)服务网关 Zuul Filter 使用

    上一篇文章中,讲了Zuul 转发,动态路由,负载均衡,等等一些Zuul 的特性,这个一篇文章,讲Zuul Filter 使用,关于网关的作用,这里就不再次赘述了,重点是zuul的Filter ,我们可 ...

  2. Spring Cloud(六)服务网关 zuul 快速入门

    服务网关是微服务架构中一个不可或缺的部分.通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由.均衡负载功能之外,它还具备了权限控制等功能.Spring Cloud Netflix中 ...

  3. Spring Cloud 系列之 Gateway 服务网关(四)

    本篇文章为系列文章,未读第一集的同学请猛戳这里: Spring Cloud 系列之 Gateway 服务网关(一) Spring Cloud 系列之 Gateway 服务网关(二) Spring Cl ...

  4. Spring Cloud 系列之 Gateway 服务网关(二)

    本篇文章为系列文章,未读第一集的同学请猛戳这里:Spring Cloud 系列之 Gateway 服务网关(一) 本篇文章讲解 Gateway 网关的多种路由规则.动态路由规则(配合服务发现的路由规则 ...

  5. Spring Cloud 系列之 Gateway 服务网关(三)

    本篇文章为系列文章,未读第一集的同学请猛戳这里: Spring Cloud 系列之 Gateway 服务网关(一) Spring Cloud 系列之 Gateway 服务网关(二) 本篇文章讲解 Ga ...

  6. Spring Cloud 系列之 Gateway 服务网关(一)

    什么是 Spring Cloud Gateway Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Netflix Zuul,其不仅提供统一的路由 ...

  7. Spring Cloud学习笔记-009

    API网关服务:Spring Cloud Zuul API网关是一个更为智能的应用服务器,它的定义类似于面向对象设计模式中的Façade模式,它的存在就像是整个微服务架构系统的门面一样,所有的外部客户 ...

  8. Spring Cloud学习笔记-005

    服务消费者 之前已经搭建好了微服务中的核心组件——服务注册中心(包括单节点模式和高可用模式).也有了服务提供者,接下来搭建一个服务消费者,它主要完成两个目标,发现服务以及消费服务.其中,服务发现的任务 ...

  9. Spring Cloud 学习笔记(一)——入门、特征、配置

    [TOC] 0 放在前面 0.1 参考文档 http://cloud.spring.io/spring-cloud-static/Brixton.SR7/ https://springcloud.cc ...

随机推荐

  1. 【参考】Linux下的Memcache安装

    服务器端主要是安装memcache服务器端.下载:http://www.danga.com/memcached/dist/memcached-1.2.2.tar.gz另外,Memcache用到了lib ...

  2. swift语言点评二十一-协议

    定义有什么,及哪些必须实现. A protocol defines a blueprint of methods, properties, and other requirements that su ...

  3. SpringCloud学习笔记(14)----Spring Cloud Netflix之Hystrix对Feign的支持

    1. Hystrix对Feign的支持 添加Feign中IUserBiz的实现类HystrixFallBack: package com.wangx.cloud.springcloud02consum ...

  4. SpringCloud学习笔记(6)----Spring Cloud Netflix之负载均衡-Ribbon的使用

    1. 什么是负责均衡? 负载均衡,就是分发请求流量到不同的服务器. 负载均衡一般分为两种 1. 服务器端负载均衡(nginx) 2. 客户端负载均衡(Ribbon) 2. 服务提供者(spring-c ...

  5. Vue中路由的使用

    在Vue中动态挂载组件 首先需要安装  cnpm install vue-router --save 在main.js中引入VueRouter 并使用 定义一个路由 创建router实例 通过rout ...

  6. phpstudy创建新站点-默认打不开

    phpstudy中Apache中httpd.conf中如下语句前#要有 #Include conf/extra/httpd-vhosts.conf

  7. Go语言的前景分析

    本文为原创文章,转载注明出处,asdfasdfasdf 欢迎扫码关注公众号flysnow_org或者网站http://www.flysnow.org/,第一时间看后续精彩文章.觉得好的话,顺手分享到朋 ...

  8. Generator 简介

    Generator 就是一种状态机,封装多个内部状态. 执行 Generator 函数会返回一个遍历器对象(),也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数.返回的遍历器对 ...

  9. 在pycharm中配置Anaconda以及pip源配置

    在学习推荐系统.机器学习.数据挖掘时,python是非常强大的工具,也有很多很强大的模块,但是模块的安装却是一件令人头疼的事情. 现在有个工具--anaconda,他已经帮我们集成好了很多工具了!an ...

  10. 在VS2013中配置QT5 win7_64

    转自 在VS2013中配置QT5 win7_64 环境: win x64 + vs2013+QT5+vs_addin 下面示例正确配置QT以及VS2013 + QT Addin开发环境: 下载VS20 ...