Spring Cloud【Finchley】-18 Zuul过滤器

简介: Spring Cloud【Finchley】-18 Zuul过滤器

20190806093230928.jpg

概述


前面几篇博文,我们梳理了zuul的基本使用、路由及容错.

我们知道,zuul包含了对请求的路由和过滤两个功能,


路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础

过滤器功能则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础

每一个进入Zuul的HTTP请求都会经过一系列的过滤器处理链得到请求响应并返回给客户端。


Spring Cloud官网中的介绍比较少 , https://cloud.spring.io/spring-cloud-static/Finchley.SR2/single/spring-cloud.html#_disable_zuul_filters


那我们就去zuul自己的官网上去看看吧 (这里我们看的是zuul1.x)


https://github.com/Netflix/zuul/wiki/How-it-Works


20190119165550454.png


Filter Types


在Spring Cloud Zuul中实现的过滤器必须包含4个基本特征:

  • 过滤类型
  • 执行顺序
  • 执行条件
  • 具体操作

我们通过zuul的源码ZuulFilter来看下, ZuulFilter是一个抽象类,并且实现了IZuulFilter接口


20190119171505812.png

20190119171553688.png


filterType:该函数需要返回一个字符串来代表过滤器的类型,而这个类型就是在HTTP请求过程中定义的各个阶段。

在Zuul中默认定义了四种不同生命周期的过滤器类型,具体如下:


pre:在请求被路由之前调用,可以利用该过滤器进行身份验证、、在集群中选择请求的微服务,记录调试信息等。

route :在路由请求时候被调用,用于构建发送给微服务的请求,并使用Apache HttpClient或Netflix Ribbon请求微服务。

post:在routing和error过滤器之后被调用,可用来为响应添加标准的HTTP header、收集统计信息和指标、将响应从微服务发送给客户端等。

error:处理请求时发生错误时被调用

20190119172542178.png


filterOrder:通过int值来定义过滤器的执行顺序,数值越小优先级越高


20190119172559833.png


shouldFilter:返回一个boolean类型来判断该过滤器是否要执行。我们可以通过此方法来指定过滤器的有效范围。


20190119172612485.png


run:过滤器的具体逻辑。在该函数中,我们可以实现自定义的过滤逻辑,来确定是否要拦截当前的请求,不对其进行后续的路由,或是在请求路由返回结果之后,对处理结果做一些加工等。


20190119172621747.png


Zuul 请求生命周期


Zuul默认定义了四个不同的过滤器类型,它们覆盖了一个外部HTTP请求到达API网关,直到返回请求结果的全部生命周期.

下图来自Zuul的官方WIKI中关于请求生命周期的图解,它描述了一个HTTP请求到达API网关之后,如何在各个不同类型的过滤器之间流转的详细过程。

20190119164218984.png

当外部HTTP请求到达API网关服务的时候,首先它会进入第一个阶段pre,在这里它会被pre类型的过滤器进行处理,该类型的过滤器主要目的是在进行请求路由之前做一些前置加工,比如请求的校验等


在完成了pre类型的过滤器处理之后,请求进入第二个阶段routing,也就是之前说的路由请求转发阶段,请求将会被routing类型过滤器处理,这里的具体处理内容就是将外部请求转发到具体服务实例上去的过程


当服务实例将请求结果都返回之后,routing阶段完成,请求进入第三个阶段post,此时请求将会被post类型的过滤器进行处理,这些过滤器在处理的时候不仅可以获取到请求信息,还能获取到服务实例的返回信息,所以在post类型的过滤器中,我们可以对处理结果进行一些加工或转换等内容


还有一个特殊的阶段error,该阶段只有在上述三个阶段中发生异常的时候才会触发,但是它的最后流向还是post类型的过滤器,因为它需要通过post过滤器将最终结果返回给请求客户端


示例

Step1 新建模块


为了区分起见,我们在父工程下新建个module microservice-gateway-zuul-filter

pom.xml 及 application.yml 基本与https://github.com/yangshangwei/SpringCloudMaster/tree/master/microservice-gateway-zuul 相同

20190119201040513.png

pom依赖

  <!-- eureka client 依赖 . Eureka不是必须的 ,在没有注册中心的情况下,也可以使用zuul -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!-- zuul 依赖 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>


application.yml配置文件

server:
  port: 4536
spring:
  application:
    name: microservice-gateway-zuul-filter
eureka:
  client:
    service-url:
      defaultZone: http://artisan:artisan123@localhost:8761/eureka
  instance:
    instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
#actuator  启用所有的监控端点 “*”号代表启用所有的监控端点,可以单独启用,例如,health,info,metrics
#  spring boot 升为 2.0 后,为了安全,默认 Actuator 只暴露了2个端点,heath 和 info
management:
  endpoints:
    web:
      exposure:
        include: "*" 
  endpoint:
      health:
        show-details: ALWAYS
zuul: 
  routes:
    microservice-provider-user: /userprovider/**
logging:
  level:
    com.netflix: DEBUG  # 将 com.netflix包的日志级别设置为debug,将打印zuul的转发细节


Step2 自定义zuul过滤器

package com.artisan.microservice.zuulFilter;
import javax.servlet.http.HttpServletRequest;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
public class PreRequestZuulFilter  extends ZuulFilter{
  @Override
  public boolean shouldFilter() {
    return true;
  }
  @Override
  public String filterType() {
    return "pre";
  }
  @Override
  public int filterOrder() {
    return 0;
  }
  @Override
  public Object run() throws ZuulException {
    HttpServletRequest request =    RequestContext.getCurrentContext().getRequest();
    System.out.println("pre filter, 请求路径:"  +request.getRequestURI());
    return null;
  }
}



自定义的zuul过滤器,需要继承 ZuulFilter,重写如上方法


filterType: 过滤器的类型,取值如下 pre route post error . 可以从源码的注释中看到

filterOrder:过滤器的执行顺序,不同的过滤器可以返回相同的数字

shouldFilter:表示该过滤器是否要执行,true执行,false不执行

run:过滤器的具体逻辑


Step3 初始化zuul过滤器


2019011920172461.png


Step4 测试

  • 启动microservice-discovery-eureka
  • 启动micorservice-provider-user
  • 启动microservice-gateway-zuul-filter
  • 访问 http://localhost:4536/userprovider/user/2


20190119201909845.png

观察 microservice-gateway-zuul-filter的日志


2019011920202798.png


禁用zuul过滤器


https://cloud.spring.io/spring-cloud-static/Finchley.SR2/single/spring-cloud.html#_disable_zuul_filters


spring cloud 默认为zuul编写并启用了一些过滤器 ,我们用的这个版本在 spring-cloud-netflix-zuul-2.0.0.RELEASE.jar 的org.springframework.cloud.netflix.zuul.filters 目录下


20190119202635753.png

禁用某个或某些过滤器,只需要 设置即可

zuul.<SimpleClassName>.<filterType>.disable=true


举个例子,比如上面自定义的zuul filter, 我们过想禁用的话,两种方式

  1. 第一种方式:重写shouldFilter逻辑,返回false
  2. 第二种方式:application.yml中设置disable属性为true ,如下


20190119204301301.png

经测试,生效,日志中没有打印run中的输出。


代码

https://github.com/yangshangwei/SpringCloudMaster/tree/master/microservice-gateway-zuul-filter


20190413更新

Pre和Post过滤器(补充示例)

package com.artisan.apigateway.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
@Component
public class TokenFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return PRE_TYPE;
    }
    @Override
    public int filterOrder() {
        return PRE_DECORATION_FILTER_ORDER - 1;
    }
    @Override
    public boolean shouldFilter() {
        return true;
    }
    @Override
    public Object run() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        //这里从url参数里获取, 也可以从cookie, header里获取
        String token = request.getParameter("token");
        if (StringUtils.isEmpty(token)) {
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null;
    }
}



返回值推荐使用FilterConstants类提供的常量

package com.artisan.apigateway.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.POST_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_RESPONSE_FILTER_ORDER;
@Component
public class AddResponseHeaderFilter extends ZuulFilter{
    @Override
    public String filterType() {
        return POST_TYPE;
    }
    @Override
    public int filterOrder() {
        return SEND_RESPONSE_FILTER_ORDER - 1;
    }
    @Override
    public boolean shouldFilter() {
        return true;
    }
    @Override
    public Object run() {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletResponse response = requestContext.getResponse();
        response.setHeader("X-Foo", UUID.randomUUID().toString());
        return null;
    }
}


相关文章
|
16天前
|
JavaScript Java Kotlin
深入 Spring Cloud Gateway 过滤器
Spring Cloud Gateway 是新一代微服务网关框架,支持多种过滤器实现。本文详解了 `GlobalFilter`、`GatewayFilter` 和 `AbstractGatewayFilterFactory` 三种过滤器的实现方式及其应用场景,帮助开发者高效利用这些工具进行网关开发。
|
20天前
|
消息中间件 监控 Java
如何将Spring Boot + RabbitMQ应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot + RabbitMQ应用程序部署到Pivotal Cloud Foundry (PCF)
31 6
|
20天前
|
Java 关系型数据库 MySQL
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot + MySQL应用程序部署到Pivotal Cloud Foundry (PCF)
39 5
|
20天前
|
缓存 监控 Java
如何将Spring Boot应用程序部署到Pivotal Cloud Foundry (PCF)
如何将Spring Boot应用程序部署到Pivotal Cloud Foundry (PCF)
31 5
|
3月前
|
Java 开发者 Spring
Spring Cloud Gateway 中,过滤器的分类有哪些?
Spring Cloud Gateway 中,过滤器的分类有哪些?
78 3
|
3月前
|
负载均衡 Java 网络架构
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
实现微服务网关:Zuul与Spring Cloud Gateway的比较分析
160 5
|
5月前
|
负载均衡 Java Spring
Spring cloud gateway 如何在路由时进行负载均衡
Spring cloud gateway 如何在路由时进行负载均衡
580 15
|
5月前
|
Java Spring
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
spring cloud gateway在使用 zookeeper 注册中心时,配置https 进行服务转发
126 3
|
Dubbo Java 应用服务中间件
深入了解Spring Cloud Alibaba Dubbo
在现代分布式系统开发中,构建高性能、可伸缩性和弹性的微服务架构变得越来越重要。Spring Cloud Alibaba Dubbo(简称Dubbo)是一个开源的分布式服务框架,可以帮助开发者构建强大的微服务架构,具备负载均衡、服务治理、远程调用等强大功能。本文将深入介绍Spring Cloud Alibaba Dubbo,帮助你理解它的核心概念、工作原理以及如何在你的项目中使用它。
|
Kubernetes Java 微服务
Spring Boot 单体应用一键升级成 Spring Cloud Alibaba(1)
Spring Boot 单体应用一键升级成 Spring Cloud Alibaba(1)
148 0
Spring Boot 单体应用一键升级成 Spring Cloud Alibaba(1)
下一篇
DataWorks