博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring Cloud Zuul 过滤器
阅读量:5878 次
发布时间:2019-06-19

本文共 6874 字,大约阅读时间需要 22 分钟。

hot3.png

Spring Cloud Zuul 除了可以实现请求的路由功能,还有一个重要的功能就是过滤器。Zuul 的路由功能让所有的微服务提供的接口有统一的网关入口,但并不是所有的接口都是对外完全开发的,它们的访问权限一般都有一定的限制。那我们可以在每个服务都加上对应的校验和权限鉴定,那这些通常都是用过滤器或拦截器实现的,而且一个系统的各个服务的校验也大都是相似,这些相似的校验逻辑打码在每个服务都会有一份,不仅冗余且维护麻烦。更好的办法就是在请求的最前端统一去做这样的事情,而统一的 API 服务网关入口就是合适的选择

Zuul 可以通过定义过滤器来实现请求的拦截和过滤,而它本身的大部分功能也是通过过滤器实现的

过滤器

在 Zuul 中自定义过滤器需要继承抽象类 ZuulFilter,需要实现以下4个方法:

String filterType(); // 过滤器类型int filterOrder(); // 执行顺序,数值越小优先级越高                      boolean shouldFilter(); // 执行过滤器的条件Object run() throws ZuulException; // 具体的过滤操作

从名字我们也能知道各个方法的作用,下面来了解下过滤器类型和过滤器的生命周期,以及自定义过滤器的使用

过滤器类型和生命周期

Zuul 定义了4种不同的过滤器类型,对应着请求的典型生命周期

  • PRE: 在请求被路由之前执行。可以用于请求身份验证、选择源服务器和记录调试信息
  • ROURING: 该过滤器将请求路由到服务。用于构建和发送给微服务的请求(使用 Apache HttpClient 或 Netflix Ribbon 请求服务)
  • POST: 在请求被路由到服务之后执行。可以用于向响应添加标准的 HTTP Header、收集统计数据和指标,以及将响应从源服务发送到客户端
  • ERROR: 该过滤器在其他阶段发生错误时执行

除了默认的过滤器流,Zuul 还允许我们创建自定义过滤器类型并显式地执行它们。例如,我们可以自定义一个 STATIC 类型的过滤器,它在Zuul 中生成响应,而不是将请求转发到后端的服务

下面是 Zuul 的生命周期图,描述着各种类型的过滤器的执行顺序(图片来源于 )

Zuul 的生命周期图

Spring Cloud Zuul 的过滤器

Spring Cloud Zuul 作为服务网关的大部分功能都是通过过滤器实现的,它在请求的各个阶段实现了一系列的过滤器,在 Spring Cloud Zuul 网关服务启动时自动加载和启用。实现的这些过滤器是在 spring-cloud-netflix-zuul 模块中的 org.springframework.cloud.netflix.zuul.filters 包下面

下面介绍部分过滤器的功能

Pre filters

filter order 说明
ServletDetectionFilter -3 检测请求是否通过 Spring 调度程序,即判断请求是交由 Spring DispatcherServlet 处理,还是 ZuulServlet 处理(主要是用于大文件上传)
Servlet30WrapperFilter -2 把原始 HttpServletRequest 包装成 Servlet30RequestWrapper 对象
FormBodyWrapperFilter -1 解析表单数据并为下游服务重新编码
DebugFilter 1 如果设置 debug 请求参数,则此过滤器将RequestContext.setDebugRouting() 和 RequestContext.setDebugRequest() 设置为true
PreDecorationFilter 5 根据提供的 RouteLocator 确定路由的位置和方式,它还为下游请求设置各种与代理相关的头文件

Route filters

filter order 说明
RibbonRoutingFilter 10 使用 Ribbon、Hystrix 和 可插拔 HTTP客户机发送请求。只对 RequestContext 存在 serviceId 参数的请求进行处理,即只对通过 serviceId配置路由规则的请求路由。可以使用不同的 HTTP 客户端:HttpClient、OkHttpClient、Netflix Ribbon HTTP client
SimpleHostRoutingFilter 100 通过 Apache HttpClient 发送请求到预定的 url,这些 url 可以在 RequestContext.getRouteHost() 中找到,即只对通过 url 配置路由规则的请求路由
SendForwardFilter 500 通过使用 Servlet RequestDispatcher 转发请求。用于转发请求到当前应用的端点

Post filters

filter order 说明
LocationRewriteFilter 900 负责将 Location header 重写为 Zuul URL
SendResponseFilter 1000 将代理请求的响应写入当前响应

Error filters

filter order 说明
SendErrorFilter 0 利用请求上下文中的错误信息来组织成一个 forward 到 /error 错误端点的请求来产生错误响应

禁用过滤器

默认情况下,这些过滤器在代理和服务器模式下都是启用的。如果在某些场景下,禁用某个过滤器,可以设置 zuul.<SimpleClassName>.<filterType>.disable=true。例如,要禁用org.springframework.cloud.netflix.zuul.filter.post.sendresponsefilter,设置 zuul.SendResponseFilter.post.disable=true

自定义过滤器

创建一个 Spring Boot 项目 zuul-filters,Zuul 的服务网关路由配置可以见

spring:  application:    name: zuul-filtersserver:  port: 8090eureka:  client:    service-url:      defaultZone: http://localhost:8761/eureka/zuul:  ignoredServices: '*'  routes:    product:      path: /product/**      serviceId: product-servicemanagement:  endpoints:    web:      exposure:        include: '*'

自定义一个过滤器 AccessFilter,对请求中没有 accessToken 参数的请求,返回 401拒绝访问

@Log4j2public class AccessFilter extends ZuulFilter {    @Override    public int filterOrder() {        // run before PreDecoration        return FilterConstants.PRE_DECORATION_FILTER_ORDER - 1;    }    @Override    public String filterType() {        return FilterConstants.PRE_TYPE;    }    @Override    public boolean shouldFilter() {        RequestContext ctx = RequestContext.getCurrentContext();        // a filter has already forwarded        // a filter has already determined serviceId        return !ctx.containsKey(FilterConstants.FORWARD_TO_KEY)                && !ctx.containsKey(FilterConstants.SERVICE_ID_KEY);    }    @Override    public Object run() {        RequestContext ctx = RequestContext.getCurrentContext();        HttpServletRequest request = ctx.getRequest();        log.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString());        String token = request.getParameter("accessToken");        if(StringUtils.isBlank(token)) {            log.warn("access token is empty");            // 过滤该请求,不对其进行路由            ctx.setSendZuulResponse(false);            ctx.setResponseStatusCode(401);            return null;        }        log.info("access token ok");        return null;    }}

实现自定义过滤器后,把它添加到 Spring 的 Beans 中

@SpringBootApplication@EnableZuulProxypublic class ZuulFiltersApplication {    public static void main(String[] args) {        SpringApplication.run(ZuulFiltersApplication.class, args);    }    @Bean    public AccessFilter accessFilter() {        return new AccessFilter();    }}

下面我们来测试下结果,启动项目 eureka-serverproduct-serivce(作为代理的服务)、zuul-filters

访问 http://localhost:8090/product/product/1 返回 401

访问 http://localhost:8090/product/product/1?accessToken=111 会正常路由到 product-service 的 /product/1

参考代码见:

过滤器管理端点

@EnableZuulProxy 注解配合 Spring Boot Actuator,Zuul 会暴露额外的两个管理端点:RoutesFilters。分别是关于路由和过滤器的端点(服务路由的端点在这里介绍 )

spring-cloud-starter-netflix-zuul 已经依赖了 spring-boot-starter-actuator,所以上面的工程已经包含了路由管理的功能。关于过滤器的管理端点的路径为 /filters

访问路径

{  "error": [    {      "class": "org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter",      "order": 0,      "disabled": false,      "static": true    }  ],  "post": [    {      "class": "org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter",      "order": 1000,      "disabled": false,      "static": true    }  ],  "pre": [    {      "class": "org.springframework.cloud.netflix.zuul.filters.pre.DebugFilter",      "order": 1,      "disabled": false,      "static": true    },    {      "class": "org.springframework.cloud.netflix.zuul.filters.pre.FormBodyWrapperFilter",      "order": -1,      "disabled": false,      "static": true    },    {      "class": "com.turbosnail.zuul.filter.AccessFilter",      "order": 4,      "disabled": false,      "static": true    },    {      "class": "org.springframework.cloud.netflix.zuul.filters.pre.Servlet30WrapperFilter",      "order": -2,      "disabled": false,      "static": true    },    {      "class": "org.springframework.cloud.netflix.zuul.filters.pre.ServletDetectionFilter",      "order": -3,      "disabled": false,      "static": true    },    {      "class": "org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter",      "order": 5,      "disabled": false,      "static": true    }  ],  "route": [    {      "class": "org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter",      "order": 100,      "disabled": false,      "static": true    },    {      "class": "org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter",      "order": 10,      "disabled": false,      "static": true    },    {      "class": "org.springframework.cloud.netflix.zuul.filters.route.SendForwardFilter",      "order": 500,      "disabled": false,      "static": true    }  ]}

访问404是因为没有暴露端点,可以设置 management.endpoints.web.exposure.include: '*'

转载于:https://my.oschina.net/morgan412/blog/3050858

你可能感兴趣的文章
WinForm程序中两份mdf文件问题的解决
查看>>
【转】唯快不破:创业公司如何高效的进行产品研发管理
查看>>
程序计数器、反汇编工具
查看>>
Android N: jack server failed
查看>>
007-Shell test 命令,[],[[]]
查看>>
关于Linux系统使用遇到的问题-1:vi 打开只读(readonly)文件如何退出保存?
查看>>
pandas 按照某一列进行排序
查看>>
在WPF中如何使用RelativeSource绑定
查看>>
Map的深浅拷贝的探究
查看>>
XSLT语法 在.net中使用XSLT转换xml文档示例
查看>>
如何将lotus 通讯簿导入到outlook 2003中
查看>>
WinForm 应用程序中开启新的进程及控制
查看>>
前端工程师的职业发展路线在哪?
查看>>
IOS 内存警告 Memory warning level
查看>>
[转]PAC Manager: Ubuntu 上强大的 SSH 帐号管理工具,可取代 SecureCRT_Miracle_百度空间...
查看>>
顺序容器 (2)string类型操作
查看>>
转载:我最近的研究成果(IGeometry.Project and IGeometry.SpatialReference)
查看>>
提示框
查看>>
HDOJ1233 畅通工程之一(最小生成树-Kruscal)
查看>>
14Spring_AOP编程(AspectJ)_环绕通知
查看>>