目录

  • SpringCloud Gateway
  • 几个重要概念
  • 路由(Route)
  • 谓词(Predicate)
  • 过滤器(Filter)
  • 工作原理
  • 配置方式
  • 快捷配置
  • 完全扩展参数配置
  • 路由谓词工厂
  • After
  • Header
  • Host
  • Method
  • Path
  • Query
  • RemoteAddr
  • Weight
  • 过滤器工厂
  • Hystrix
  • Prefix
  • StripPrefix
  • RedirectTo
  • Retry
  • Redis RateLimiter
  • 全局过滤器(GlobalFilter)


SpringCloud Gateway

SpringCloud Gateway 是一个基于 Spring 生态系统的 API 网关。基于 Spring Boot 2.x, Spring WebFlux 和 Reactor 构建。因此,使用 Spring Cloud Gateway 时,许多熟悉的同步库(例如,Spring Data 和 Spring Security )和模式可能不适用。

Spring Cloud Gateway 需要Spring Boot 和 Spring Webflux 提供的 Netty 运行时环境。它不能在传统的 Servlet 容器中或作为 WAR 包构建。

几个重要概念

路由(Route)

路由网关的基本模块。它由 ID,目标地址URI,谓词集合和过滤器集合定义。如果聚合谓词为true,则匹配路由。

谓词(Predicate)

Java 8 Function谓词。输入类型为 Spring Framework ServerWebExchange。这使开发人员可以匹配HTTP请求中的任何内容,例如请求头或参数。

过滤器(Filter)

这些是使用特定工厂构造的 Spring Framework GatewayFilter 实例。在此,可以在发送下游请求之前或之后修改请求和响应。

工作原理

springcloud路由reewrite springcloud gateway 路由_Cloud

客户端向 Spring Cloud Gateway 发出请求。如果网关处理程序映射(Gateway Handler Mapping )确定请求与路由匹配,则将其发送到网关Web处理程序(Gateway Web Handler)。该处理程序通过特定于请求的过滤器链运行请求。过滤器由虚线分隔的原因是,过滤器可以在发送代理请求之前或之后执行逻辑。执行所有“前置”过滤器逻辑,然后发出代理请求。发出代理请求后,将执行“后置”过滤器逻辑。

配置方式

有两种配置谓词和过滤器的方法:快捷配置和完全扩展参数配置。

快捷配置

快捷配置通过过滤器名称标识,后跟等号(=),再跟由逗号分隔的参数值(,)。

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://zysite.top
        predicates:
        - Cookie=mycookie,mycookievalue

上面的示例使用两个参数定义了Cookie 路由谓词工厂,即 cookie 名称与mycookie匹配以及 cookie 的值与mycookievalue匹配的请求。

完全扩展参数配置

完全扩展的参数配置看起来更像是 name/value 对的标准Yaml 配置。通常,将有一个name键和一个args键。args键是用于配置谓词或过滤器的键值对的映射。

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://zysite.top
        predicates:
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue

上面显示的Cookie谓词的快捷配置的完整配置。regexp是 Java 正则表达式。

路由谓词工厂

After

After路由谓词工厂只有一个参数,即datetime(就是Java ZonedDateTime)。该谓词匹配在当前日期时间之后发生的请求。

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://zysite.top
        predicates:
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]

该路由与2017年1月20日17:42山区时间(丹佛)之后的所有请求匹配。

与之类似的还有BeforeBetween。Between 接收两个 datetime,用逗号隔开。

还有上一部分的示例Cookie

Header

Header 路由谓词工厂具有两个参数,请求头nameregexp。该谓词与具有给定名称请求头,并且值与正则表达式匹配的请求匹配。

spring:
  cloud:
    gateway:
      routes:
      - id: header_route
        uri: https://zysite.top
        predicates:
        - Header=X-Request-Id, \d+

如果请求具有名为X-Request-Id的请求头,且其值与\d+正则表达式匹配(具有一个或多个数字的值),则此路由匹配。

Host

Host路由谓词工厂只有一个参数:主机名patterns的列表。模式是 Ant 样式的模式,以.作为分隔符。该谓词匹配请求头中的 Host。

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://zysite.top
        predicates:
        - Host=**.spring.io,**.netty.io

上面的路由匹配任意主机以spring.ionetty.io结尾发出的请求。如aa.spring.iobb.netty.io

还支持 URI 模版变量,如 Host = {sub}.spring.io,其中sub即为 URI 模版变量。可通过 ServerWebExchange.getAttributes()获得 Map,再通过 Map 的 get(“sub”) 获取。

Map<String, String> uriVariables = ServerWebExchangeUtils.getPathPredicateVariables(exchange);
String sub = uriVariables.get("sub");

Method

Method路由谓词工厂只有一个methods参数,该参数是一个或多个要匹配的 HTTP 方法。

spring:
  cloud:
    gateway:
      routes:
      - id: method_route
        uri: https://zysite.top
        predicates:
        - Method=GET,POST

该路由匹配请求方法为 GET 或 POST 的请求。

Path

Path路由谓词工厂具有两个参数:Spring PathMatcher patterns的列表和matchOptionalTrailingSeparator的可选标志。

spring:
  cloud:
    gateway:
      routes:
      - id: path_route
        uri: https://zysite.top
        predicates:
        - Path=/red/{segment},/blue/{segment}

该路由匹配请求路径以/red/blue开头的请求。如/red/aa/blue/bb。也支持 URI 模版变量。

Query

Query 路由谓词工厂具有两个参数:必需的param和可选的regexp

spring:
  cloud:
    gateway:
      routes:
      - id: query_route
        uri: https://zysite.top
        predicates:
        - Query=color,gree.

该路由匹配包含请求参数color,其值与gree.正则匹配的请求。

RemoteAddr

RemoteAddr路由谓词工厂只有一个参数:sources的列表(最小为 1),它是 CIDR 表示法(IPv4或IPv6)字符串,例如192.168.0.1/16(其中192.168.0.1是 IP 地址, 16是子网掩码)。

spring:
  cloud:
    gateway:
      routes:
      - id: remoteaddr_route
        uri: https://zysite.top
        predicates:
        - RemoteAddr=192.168.1.1/24

如果请求的远程地址为192.168.1.10192.168.1.100等,则此路由将匹配。

Weight

Weight 路由谓词工厂具有两个参数groupweight(一个int)。权重是按组计算的。

spring:
  cloud:
    gateway:
      routes:
      - id: weight_high
        uri: https://weighthigh.org
        predicates:
        - Weight=group1, 8
      - id: weight_low
        uri: https://weightlow.org
        predicates:
        - Weight=group1, 2

此路由会将约80%的流量转发到https://weighthigh.org并将约20%的流量转发到https://weightlow.org

过滤器工厂

路由过滤器允许以某种方式修改传入的 HTTP 请求或传出的 HTTP 响应。路由过滤器适用于特定路由。Spring Cloud Gateway 包括许多内置的 GatewayFilter 工厂。下面示例几个常见的,完整的可以参考 SpringCloud Gateway

Hystrix

Hystrix 是 Netflix 的一个库,它实现了断路器模式Hystrix 过滤器允许您将断路器引入网关路由,保护服务免受级联故障的影响,并允许您在下游故障的情况下提供后备响应(fallback)。

注意:要启用 Hystrix 过滤器,需引入 spring-cloud-starter-netflix-hystrix的依赖。

Hystrix 过滤器工厂只有一个必选name参数,它是HystrixCommand的名称。

spring:
  cloud:
    gateway:
      routes:
      - id: hystrix_route
        uri: https://zysite.top
        filters:
        - Hystrix=myCommandName

还可以接受可选的fallbackUri参数。当前,仅支持forward:策略的URI。如果调用了 fallback ,则请求将被转发到与URI 相匹配的控制器。

spring:
  cloud:
    gateway:
      routes:
      - id: hystrix_route
        uri: lb://backing-service:8088
        predicates:
        - Path=/consumingserviceendpoint
        filters:
        - name: Hystrix
          args:
            name: fallbackcmd
            fallbackUri: forward:/fallback
        - RewritePath=/consumingserviceendpoint, /backingserviceendpoint

当 Hystrix fallback 被调用时,会将请求转发到 Gateway 内部程序的/fallback URI 上(也可以转发到外部程序的 URI 上)。上述 lb前缀表示可以整合 Ribbon 的负载均衡。

其实 SpringCloud 还包括 CircuitBreake过滤器工厂,可以指定断路器模式的实现,如:上面的 Hystrix、Resilience4j 等。另外,还包括FallbackHeaders过滤器工厂,可以在 fallback 被调用是将一些信息添加到头部后在将请求转发到对应的fallbackUri

信息包括:

  • executionExceptionTypeHeaderName ("Execution-Exception-Type")
  • executionExceptionMessageHeaderName ("Execution-Exception-Message")
  • rootCauseExceptionTypeHeaderName ("Root-Cause-Exception-Type")
  • rootCauseExceptionMessageHeaderName ("Root-Cause-Exception-Message")

Prefix

PrefixPath过滤器工厂只有一个prefix参数。

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://zysite.top
        filters:
        - PrefixPath=/pathprefix

将会把所有请求的路径添加/pathprefix前缀后转发,如请求 URI 为/hello将变为/pathprefix/hello

StripPrefix

StripPrefix 过滤器工厂只有一个参数partsparts参数指示在向下游发送请求之前,要从请求路径中跳过的地址段数。

spring:
  cloud:
    gateway:
      routes:
      - id: nameRoot
        uri: https://nameservice
        predicates:
        - Path=/name/**
        filters:
        - StripPrefix=2

当请求地址为/name/blue/red时,发送到nameservice的地址将变为https://nameservice/red,即/name/blue这两段地址被跳过了。

RedirectTo

RedirectTo 过滤器工厂包括一个status和一个url参数。状态应该是 300 系列重定向 http 代码,例如301。URL应该是有效的URL 。这将是Location响应头的值。

spring:
  cloud:
    gateway:
      routes:
      - id: redirect_route
        uri: https://zysite.top
        filters:
        - RedirectTo=302, https://spring.io

这将发送状态码为 302 且带有Location:https://spring.io头部的响应以执行重定向。

Retry

Retry过滤器工厂支持以下参数:

  • retries:尝试重试的次数
  • statuses:应重试的 HTTP 状态码,用org.springframework.http.HttpStatus表示
  • methods:应重试的 HTTP 方法,使用org.springframework.http.HttpMethod表示
  • series:要重试的一系列状态码,使用org.springframework.http.HttpStatus.Series表示
  • exceptions:引发重试的异常列表
  • backoff:为重试配置了补偿指数。重试在补偿间隔firstBackoff * (factor ^ n)之后执行,其中n是迭代。如果配置了maxBackoff,则应用的最大补偿将被限制为maxBackoff。如果basedOnPreviousValue为true,将使用prevBackoff * factor计算补偿。
spring:
  cloud:
    gateway:
      routes:
      - id: retry_test
        uri: http://localhost:8080/flakey
        predicates:
        - Host=*.retry.com
        filters:
        - name: Retry
          args:
            retries: 3
            statuses: BAD_GATEWAY
            methods: GET,POST
            backoff:
              firstBackoff: 10ms
              maxBackoff: 50ms
              factor: 2
              basedOnPreviousValue: false

Redis RateLimiter

redis 实现基于 Stripe 所做的工作。它需要使用spring-boot-starter-data-redis-reactive starter 依赖。

使用的算法是令牌桶算法

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://zysite.top
        filters:
        - name: RequestRateLimiter
          args:
            redis-rate-limiter.replenishRate: 10
            redis-rate-limiter.burstCapacity: 20
            redis-rate-limiter.requestedTokens: 1

redis-rate-limiter.replenishRate是希望用户每秒允许多少个请求,而没有任何丢弃的请求。这是令牌桶被填充的速率。

redis-rate-limiter.burstCapacity是允许用户在一秒钟内执行的最大请求数。这是令牌桶可以容纳的令牌数。

redis-rate-limiter.requestedTokens是一个请求耗费的 token 数量,默认为1。

通过在replenishRateburstCapacity中设置相同的值可以达到稳定的速率。通过将burstCapacity设置为高于replenishRate,可以允许临时突发。

速率限制器也可以定义为实现RateLimiter接口的bean。在配置中,使用SpEL通过名称引用bean。#{@myRateLimiter}是一个SpEL表达式,引用名称为myRateLimiter的bean。

spring:
  cloud:
    gateway:
      routes:
      - id: requestratelimiter_route
        uri: https://zysite.top
        filters:
        - name: RequestRateLimiter
          args:
            rate-limiter: "#{@myRateLimiter}"
            key-resolver: "#{@userKeyResolver}"

还有很多过滤器工厂没有提到,像 添加请求头/响应头,添加/删除请求参数,删除响应头,重写请求路径,修改响应体等等。官方文档有详细解释。

全局过滤器(GlobalFilter)

GlobalFilter接口具有与GatewayFilter类似的含义,只不过GatewayFilter只针对匹配了特定路由的请求进行处理,而GlobalFilter则对所有请求都进行处理。

当一个请求到达 Gateway,网关Web处理程序(Gateway Web Handler)将会把GlobalFilter和匹配的GatewayFilter组成一个过滤器链(根据优先级,即 Order 接口返回的值,越小优先级越高,可以为负值)。

一个简单的全局过滤器实现如下:

@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("custom global filter");
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1;
    }
}

SpringCloud 还有一些内置的全局过滤器,如:LoadBalancerClientFilterNettyRoutingFilter等等。可在官网或者源码org.springframework.cloud.gateway.filter包中查看。