Spring Cloud Gateway


Spring Cloud Gateway提供一个spring生态系统之上的api网关,由Spring5,Spring Boot2和Reactor组成。旨在提供一个简单,并且高效的api路由功能和横切某些关注点,例如安全、监控和弹性化。

一、如何导入使用Spring Cloud Gateway

在引入了Spring Boot和SpringCloud的maven项目中:

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

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-webflux</artifactId>
 </dependency>

如果引入了SpringCloud Gateway Starter,但不希望启用网关,可在配置文件中设置 spring.cloud.gateway.enabled=false。Spring Cloud Gateway 基于 Spring Boot 2.x、Spring WebFlux 和 Project Reactor 构建。因此,许多熟悉的同步库(例如Spring Data and Spring Security)和你知道的某些模式在使用 Spring Cloud Gateway 时可能不适用。Spring Cloud Gateway 需要 Spring Boot 和 Spring Webflux 提供的 Netty 运行时。它不适用于传统的 Servlet 容器或构建为 WAR 包项目。

二、Gateway相关概念

  • Route:gateway中最基本的组成块,由一个ID,一个目的URI,一组断言,和一组过滤器组成。当组中断言都为真时才会匹配该路由。
  • Predicate:这是一个java8中的函数式接口Predicate,输入类型是 Spring Framework ServerWebExchange。这使你可以匹配来自 HTTP 请求的任何内容,例如标头或参数。
  • Filter:Filter是使用特定工厂构建的 GatewayFilter 实例。在Filter中,你可以在发送下游请求之前或之后修改请求和响应。
routes:
    - id: gby-auth
      uri: lb://gby-auth
      predicates:
        - Path=/api/auth/**
      filters:
        - StripPrefix=2

三、Gateway工作流程

下图提供了SpringCloud Gateway如何工作的高级抽象表示:

在这里插入图片描述
客户端发起请求到Spring Cloud Gateway,如果Gateway Handler Mapping判断该请求匹配了一个route,该请求就会被发送给Gateway Web Handler。Gateway Web Handler通过一组过滤器链对请求进行过滤处理。当过滤器执行完后,会生成一个代理请求,代理请求再将响应交给后置过滤器进行过滤处理,然后将过滤后的响应交给Gateway Web Handler,Gateway Web Handler再交给Gateway Handler Mapping,Gateway Handler Mapping返回给请求客户端。

四、配置路由断言和网关过滤器

有两种方式可以配置断言和过滤器,简洁方式和全限定方式

1、简洁方式

简洁方式通过过滤器名称识别,后接等于号(=),等于号后就是名称和匹配规则,例如:

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - Cookie=mycookie,mycookievalue

该例中,断言的过滤类型为Cookie,cookie的name为mycookie,值为mycookievalue,也就是说当请求的Cookie中有mycookie这个cookie并且值为mycookievalue时才会匹配该路由。

2、全限定方式

全限定方式就是要将一个断言的各个部分具体指明:

spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        - name: Cookie
          args:
            name: mycookie
            regexp: mycookievalue

五、断言的种类

1、After Predicate

After Predicate接收一个时间戳参数,在该时间戳之后的请求都视为匹配:

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

此路由匹配 2017 年 1 月 20 日 17:42 (美国丹佛)之后提出的任何请求。

2、Before Predicate

与After类似,该Predicate匹配指定时间戳之前的任何请求:

spring:
  cloud:
    gateway:
      routes:
      - id: before_route
        uri: https://example.org
        predicates:
        - Before=2017-01-20T17:42:47.789-07:00[America/Denver]

此路由匹配 2017 年 1 月 20 日 17:42 (美国丹佛)之前提出的任何请求。

3、Between Predicate

Between Predicate接收两个时间戳参数,匹配请求时间为两个时间戳之间的请求:

spring:
  cloud:
    gateway:
      routes:
      - id: between_route
        uri: https://example.org
        predicates:
        - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]

此路由匹配 2017 年 1 月 20 日 17:42 (美国丹佛)之后和 2017 年 1 月 21 日 17:42(美国丹佛)之前的任何请求。这对于维护窗口可能很有用。

4、Cookie Predicate

Cookie Predicate接收两个参数,cookie名和关于cookie值的正则表达式,匹配具有给定名称且其值与正则表达式匹配的 cookie。

spring:
  cloud:
    gateway:
      routes:
      - id: cookie_route
        uri: https://example.org
        predicates:
        - Cookie=chocolate, ch.p

此路由匹配具有名为 Chocolate 的 cookie 的请求,该 cookie 的值与 ch.p 正则表达式匹配。

5、Header Predicate

和Cookie Predicate类似,Header Predicate接收两个参数,一个name和关于其值的正则表达式,匹配具有给定name的标头且该标头的值需与正则表达式匹配:

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

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

6、Host Predicate

Host Predicate接收一个参数:主机名模式列表。该模式是 Ant 风格的模式,带有 .作为分隔符。匹配与模式列表中的模式匹配的 Host 标头:

spring:
  cloud:
    gateway:
      routes:
      - id: host_route
        uri: https://example.org
        predicates:
        - Host=**.somehost.org,**.anotherhost.org

如果请求具有值为 www.somehost.org 或 beta.somehost.org 或 www.anotherhost.org 的 Host 标头,则此路由匹配。

7、Method Predicate

Method Predicate接收一个方法参数,可以是一个或多个(以逗号分割):来匹配指定的 HTTP 方法。

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

如果请求方法是 GET 或 POST,则此路由匹配。

8、Path Predicate

Path Route Predicate 接受两个参数:Spring PathMatcher 模式列表和名为 matchOptionalTrailingSeparator 的可选标志:

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

如果请求路径是/red/1 或 /red/blue 或 /blue/green,则此路由匹配。
该Predicate会提取 URI 中的模板变量(例如前面示例中定义的segment)作为名称和值的映射,并使用在 ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE 中定义的键将其放置在 ServerWebExchange.getAttributes() 中。然后这些值可供 GatewayFilte使用。

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

String segment = uriVariables.get("segment");

六、Gateway中的内置Filter

Route Filter允许以某种方式修改传入的 HTTP 请求或传出的 HTTP 响应。Spring Cloud Gateway 包括许多内置的 GatewayFilter。

1、PrefixPath Filter

PrefixPath GatewayFilter 接收一个前缀参数,将该前缀加在请求路径之前:

spring:
  cloud:
    gateway:
      routes:
      - id: prefixpath_route
        uri: https://example.org
        filters:
        - PrefixPath=/mypath

将 /mypath 前缀为所有匹配请求的路径。因此,对 /hello 的请求将被发送到 /mypath/hello。

2、StripPrefix Filter

StripPrefix Filter接收一个参数,该参数指明路径剥去的层数,例如:

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

当通过网关向 /name/blue/red 发出请求时,对 nameservice 发出的请求看起来像 https://nameservice/red。

七、Global Filter

GlobalFilter接口与GatewayFilter具有相同的功能,你可以通过实现GlobalFilter接口来编写你自己的过滤处理,SpringCloud Gateway也提供了许多内置的GlobalFilter,这些特殊的过滤器在特定条件下会应用于所有的路由。

1、整合GlobalFilter和GatewayFilter的顺序
当一个请求匹配一个路由时,web过滤器handler会将所有的GlobalFilter实例和匹配该路由的所有GatewayFilter实例添加到过滤器链。过滤器链中过滤器的顺序通过org.springframework.core.Ordered接口的getOrder()方法来决定。
由于 Spring Cloud Gateway 区分过滤器逻辑执行的“前”和“后”阶段,具有最高优先级的过滤器是“前”阶段的第一个和“后”阶段的最后一个 阶段。
以下代码示例了如何配置过滤器在过滤器链中的顺序:

@Bean
public GlobalFilter customFilter(){
    return new CustomeGlobalFilter();
}

public class CustomeGlobalFilter 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;
    }
}            

八、TLS和SSL

可以通过简单的配置来使Gateway用于HTTPS请求,例如:

server:
  ssl:
    enabled: true
    key-alias: scg
    key-store-password: scg1234
    key-store: classpath:scg-keystore.p12
    key-store-type: PKCS12
    
spring:
  cloud:
    gateway:
      httpclient:
        ssl:
          useInsecureTrustManager: true

使用一个不安全的trust manager并不适合生产环境,更好是配置一些著名的证书,例如:

spring:
  cloud:
    gateway:
      httpclient:
        ssl:
          trustedX509Certificates:
          - cert1.pem
          - cert2.pem

gateway维护了一个client池来将请求路由到后端,当使用HTTPS通信时,client会启动TLS握手,许多超时与此握手相关,你可以像下面这样配置这些超时时间:

spring:
  cloud:
    gateway:
      httpclient:
        ssl:
          handshake-timeout-millis: 10000
          close-notify-flush-timeout-millis: 3000
          close-notify-read-timeout-millis: 0

九、路由配置

Spring Cloud Gateway的配置由一个RouteDefinitionLocator 集合加载,RouteDefinitionLocator 接口定义如下:

public interface RouteDefinitionLocator{
    Flux<RouteDefinition> getRouteDefinitions();
}

默认情况下,通过SpringBoot的@ConfigurationProperties机制将配置文件中的配置读取到PropertiesRouteDefinitionLocator。

在某些gateway的使用场景中,配置文件进行属性配置是足够的,但在某些情况下需要从数据库、redis、MongoDB中加载配置文件,这时可以通过实现RouteDefinitionRepository的 refreshRoutes()方法实现。

十、Route元数据配置

可以使用元数据为每个路由配置附加参数,如下所示:

spring:
  cloud:
    gateway:
      routes:
      - id: route_with_metadata
        uri: https://example.org
        metadata:
          optionName: "OptionValue"
          compositeObject:
            name: "value"
          iAmNumber: 1

然后从exchange中获取它们:

Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
// 获取所有元数据
route.getMetadata();
// 根据key获取一个元数据
route.getMetadata("optionName");

十一、HTTP超时配置

HTTP超时(包括响应超时和连接超时)可以被应用于所有的Route或部分限定路由。
1、Global timeouts
意如其名,用于配置http全局超时

spring:
  cloud:
    gateway:
      httpclient:
        # 单位毫秒
        connect-timeout: 1000
        response-timeout: 5s

2、单个路由的超时

- id: per_route_timeouts
        uri: https://example.org
        predicates:
          - name: Path
            args:
              pattern: /delay/{timeout}
        metadata:
          response-timeout: 200
          connect-timeout: 200

或者通过Java代码:

import static org.springframework.cloud.gateway.support.RouteMetadataUtils.CONNECT_TIMEOUT_ATTR;
import static org.springframework.cloud.gateway.support.RouteMetadataUtils.RESPONSE_TIMEOUT_ATTR;

      @Bean
      public RouteLocator customRouteLocator(RouteLocatorBuilder routeBuilder){
         return routeBuilder.routes()
               .route("test1", r -> {
                  return r.host("*.somehost.org").and().path("/somepath")
                        .filters(f -> f.addRequestHeader("header1", "header-value-1"))
                        .uri("http://someuri")
                        .metadata(RESPONSE_TIMEOUT_ATTR, 200)
                        .metadata(CONNECT_TIMEOUT_ATTR, 200);
               }).route(r -> r.order(-1)
                .host("**.throttle.org").and().path("/get")
                .filters(f -> f.filter(throttle.apply(1,
                        1,
                        10,
                        TimeUnit.SECONDS)))
                .uri("http://httpbin.org:80")
                .metadata("key", "value")
            )
               .build();
      }

3、Discovery 路由配置
你可以将网关配置为基于向 DiscoveryClient 兼容的服务注册表注册的服务创建路由。

要启用此功能,需设置 spring.cloud.gateway.discovery.locator.enabled=true 并确保 DiscoveryClient 的实现(例如 Netflix Eureka、Consul 或 Zookeeper)在类路径上并已启用。

十二、跨域配置

你可以通过配置来控制gateway的跨域行为,“全局”CORS 配置是 URL 模式到 Spring Framework CorsConfiguration 的映射。 以下示例配置 CORS:

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowedOrigins: "https://docs.spring.io"
            allowedMethods:
            - GET

在上面的例子中,允许来自docs.spring.io的所有get跨域请求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值