三、Spring Cloud Gateway

    Spring Cloud Gateway是Spring Cloud大家族的一个新进成员,在Spring Cloud 2.0之后用于取代非官方的Zuul。Getaway基于Spring 5.0与Spring WebFlux开发,采用Reactor-netty响应式设计。

    1、请求流程:

        客户端发起请求到达Gateway,根据HandlerMapping中找到与请求相匹配的路由,将其发送到Gateway Web Handler,Handler再通过指定的过滤器链将请求发送到我们实际的服务项目中执行业务逻辑,然后返回。

Spring Security hasIpAddress实现ip白名单 spring cloud gateway 白名单_gateway

        术语:

            路由(Route):路由为一组断言与一组过滤器的集合,它是网关的一个基本组件。

            断言(Predicate):匹配路由的判断条件,例如Path=/demo,匹配后应用路由。

            过滤器(Filter):过滤器可以对请求和返回进行修改,比如增加头信息等。

            地址(URL):匹配路由后转发的地址。

    2、配置原理

        (1)、包依赖:依赖spring-boot-starter-webflux和spring-cloud-starter

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

        (2)、继承DispatcherHandler重新实现分发逻辑(类似Zuul),扩展DispatcherHandler的组件HandlerMapping。

    3、功能

        (1)、Gateway跨域访问

        (2)、Gateway过滤器

            Spring Cloud Gateway的Filter类型只有两个:"pre"和”post"。

            Spring Cloud Gateway的Filter分为两种:GatewayFilter和Globalfilter。

        (3)、Gateway请求匹配

            Gateway网关可以根据不同的方式进行匹配进而把请求分发到不同的后端服务上,通过header进行匹配,把请求分发到不同的服务上。可以通过POST、GET、PUT、DELTE等不同的方式进行路由。

        (4)、Gateway熔断

            Spring Cloud Gateway也可以利用Hystrix的熔断特性,在流量过大时进行服务降级,同时项目中必须加上Hystrix的依赖。

        (5)、Gateway重试路由器

            Spring Cloud Gateway支持请求重试功能。

        (6)、Gateway限流操作

            Spring Cloud Gateway本身集成了限流操作,Gateway限流需要使用Redis。

    4、Gateway过滤器

        (1)、Spring Cloud Gateway的Filter类型只有两个:"pre"和"post":

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

                post:这种过滤器在路由到服务器之后执行。这种过滤器可用来为响应添加HTTP Header、统计信息和指标、响应从微服务发送给客户端等。

        (2)、Spring Cloud Gateway的Filter分为两种:

            GatewayFilter和Globalfilter:GlobalFilter会应用到所有的路由上,而Gatewayfilter将应用到单个路由或者一个分组的路由上。利用GatewayFilter可以修改请求的Http的请求或者是响应,或者根据请求或者响应做一些特殊的限制。更多时候可以利用GatewayFilter做一些具体的路由配置。

    5、Gateway重试路由器

        Retry GatewayFilter通过四个参数来控制重试机制:

        (1)、retries:重试次数,默认值是 3 次。

        (2)、statuses:HTTP的状态返回码,取值请参考:org.springframework.http.HttpStatus。

        (3)、methods:指定哪些方法的请求需要进行重试逻辑,默认值是 GET 方法,取值参考:org.springframework.http.HttpMethod。

        (4)、series:一些列的状态码配置,取值参考:org.springframework.http.HttpStatus.Series。符合的某段状态码才会进行重试逻辑,默认值是 SERVER_ERROR,值是 5,也就是 5XX(5 开头的状态码),共有5个值。

    6、Gateway 限流操作

        Spring Cloud Gateway本身集成了限流操作,Gateway限流需要使用Redis。需要配置RequestRateLimiter的限流过滤器,其配置参数:

        (1)、BurstCapacity:令牌桶的总容量。

        (2)、ReplenishRate:令牌通每秒填充平均速率。

        (3)、Key-resolver:用于限流的解析器的Bean对象的名字。它使用SpEL表达式#{@beanName}从Spring容器中获取bean对象。

        注:Filter下的name必须是RequestRateLimiter。

    7、Spring Cloud Gateway和Netflix Zuul的区别

        (1)、Gateway使用了流式编程,Zuul没有,相比而言Zuul代码更加简洁易懂。

        (2)、Gateway很好的支持异步,而Zuul仅支持同步。

        (3)、Gateway对比Zuul多依赖了spring-webflux,在spring的支持下内部实现了限流、负载均衡等功能,但同时也限制了仅适合于Spring Cloud套件。Zuul可以扩展至其他微服务框架中,但其内部没有实现限流、负载均衡等功能。

        (4)、从框架设计的角度看,Gateway具有更好的扩展性,并且其已经发布了2.0.0的RELESE版本,稳定性也是非常好。

    8、配置实现

        (1)、配置pom

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

        (2)、配置yml

spring:
  cloud:
    gateway:
#      开启基于注册中心的路由表,gateway可以通过开启以下配置来打开根据服务的serviceId来匹配路由。
      discovery:
        locator:
          enabled: true
      routes:
#        路由ID,要求唯一,建议配服务名
        - id: demo01
#          提供服务的应用名
          uri: lb://deom
#          断言
          predicates:
#            请求路径匹配/testController/getInfoByCondition则会进行路由
            - Path=/testController/getInfoByCondition/**
#            请求路径需要在该上海时间之后访问,才会进行路由
            - After=2020-10-20T17:42:47.789+08:00[Asia/Shanghai]
#            请求的cookie中存在key为username,value为zzyy
            - Cookie=username,zzyy
#            加请求头Host参数需要有somehost.org
            - Host=**.somehost.org
#            Get请求才会被路由
            - Method=GET
#            包含参数baz并且值匹配ba表达式则会被路由
            - Query=foo, ba
          filters:
#          对于所有匹配的请求,这会将x-response-foo:bar头添加到下游响应的header中
          - AddRequestHeader=X-Request-Foo, Bar
#          将给所有匹配请求的路径加前缀/mypath。因此,向/hello发送的请求将发送到/mypath/hello。
          - PrefixPath=/mypath

        (3)、配置自定义GlobalFilter

@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {

    /**
     * 具体过滤方法
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//        取请求参数name
        String name = exchange.getRequest().getQueryParams().getFirst("name");
        if(name == null){
            LogUtil.info("*****该用户名为null,非法用户!");
//            设置错误码
            exchange.getResponse().setStatusCode(HttpStatus.HTTP_VERSION_NOT_SUPPORTED);
            return exchange.getResponse().setComplete();
        }
//        去过滤链中的下一个Filter进行过滤
        return chain.filter(exchange);
    }

    /**
     * Filter排序方法,数字越小过滤链中的位置越靠前,越先执行
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}