概述

官网地址

是什么

  • This project provides an API Gateway built on top of the Spring Ecosystem, including: Spring 5, Spring Boot 2 and Project Reactor. Spring Cloud Gateway aims to provide a simple, yet effective way to route to APIs and provide cross cutting concerns to them such as: security, monitoring/metrics, and resiliency.

  • Gateway是在Spring生态系统之上构建的API网关服务,于Spring 5, Spring Boot 2和Project Reactor等技术。Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能,例如:熔断、限流、重试等

  • Cloud全家桶中有个很重要的组件就是网关,在1.x版本中都是采用的Zuul网关;但在2.x版本中,zuul的升级一直跳票,SpringCloud最后研发了一个SpringCloud Gateway替代Zuul

  • gateway是原zuul1.x版的替代,在Spring Cloud 2.0以上版本中,没有对新版本的Zuul 2.0以上最新高性能版本进行集成,仍然还是使用的Zuul 1.x非Reactor模式的老版本。而为了提升网关的性能,SpringCloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。

  • WebFlux https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#spring-webflux

  • Spring Cloud Gateway的目标提供统一的路由方式且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/指标,和限流。

  • 网关在微服务中的使用位置

为什么选择Gateway

  • 在SpringCloud Finchley正式版之前,Spring Cloud推荐的网关是Netlix提供的Zuul: .

  • 一方面因为Zuul1.0已经进入 了维护阶段,而且Gateway是SpringCloud团队研发的,是亲儿子产品,值得信赖。

  • Gateway是基于异步非阻塞模型上进行开发的,性能方面不需要担心。虽然Netflix早就发布 了最新的Zuul 2.x,但Spring Cloud貌似没有整合计划。而且Netflix相关组件都宣布进入维护期;不知前景如何?多方面综合考虑Gateway是很理想的网关选择。

  • SpringCloud Gateway具有如下特性

    • 基于Spring Framework 5, Project Reactor和Spring Boot 2.0进行构建; .
    • 动态路由:能够匹配任何请求属性;
    • 可以对路由指定Predicate (断言)和Filter (过滤器) ;
    • 集成Hystrix的断路器功能;
    • 集成Spring Cloud服务发现功能;
    • 易于编写的Predicate (断言)和Filter (过滤器) ;
    • 请求限流功能;
    • 支持路径重写。
  • SpringCloud Gateway与Zuul的区别

    • Zuul 1.x, 是一 个基于阻塞I/ 0的API Gateway
    • Zuul 1.x基于Servlet 2. 5使用阻塞架构它不支持任何长连接(如WebSocket) , Zuul的设计模式和Nginx较像,每次I/ 0操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但是差别是Nginx用C++实现,Zuul用Java实现,而JVM本身会有第
      一次加载较慢的情况,使得Zuul的性能相对较差。
    • Zuul 2.x理念更先进,想基于Netty非阻塞和支持长连接,但SpringCloud目前还没有整合。 Zuul 2.x的性能较Zuul 1.x有较大提升
    • 在性能方面,根据官方提供的基准测试,Spring Cloud Gateway的RPS (每秒请求数)是Zuul 的1.6倍。
    • Spring Cloud Gateway建立在Spring Framework 5、 Project Reactor和Spring Boot2之上, 使用非阻塞API。
    • Spring Cloud Gateway还支持WebSocket, 粗与Spring紧密集成拥有更好的开发体验

Zuul1.x模型

  • Springcloud中所集成的Zuul1.x版本,采用的是Tomcat容器, 使用的是传统的Servlet IO处理模型。

  • Servlet的生命周期?由servlet container进行生命周期管理。

    • container启动时构造servlet对象并调用servlet init(进行初始化;

    • container运行时接受请求,并为每个请求分配一个线程 (一般从线程池中获取空闲线程) 然后调用service()。

    • container关闭时调用servlet destory)销毁servlet;

  • 上述模式的缺点:

    • servlet是一个简单的网络IO模型,当请求进入servlet container时,servlet container就会为其绑定一个线程,在并发不高的场景下这种模型是适用
      的。但是一旦高并发(此如抽风用jemeter压),线程数量就会上涨,而线程资源代价是昂贵的(上线文切换,内存消耗大)严重影响请求的处理时间。
    • 在一些简单业务场景下,不希望为每个request分配一个线程, 只需要1个或几个线程就能应对极大并发的请求,这种业务场景下servlet模型没有优势
      所以Zuul 1.X是基于servlet之上的一个阻塞式处理模型,即spring实现了处理所有request请求的一个servlet (DispatcherServlet) 并由该servlet阻
      塞式处理处理。所以Springcloud Zuul无法摆脱servlet模型的弊端

Gateway模型

  • 基于WebFlux框架实现的

  • 传统的Web框架,此如说: struts2, springmvc等都是基于Servlet API与Servlet容器基础之上运行的。

  • 但是在Servlet3.1之后有了异步非阻塞的支持。而WebFlux是一 个典型非阻塞异步的框架,它的核心是基于Reactor的相关API实现的。相对于传统的web框架来说,它可以运行在诸如Netty, Undertow及支持Servlet3.1的容器上。非阻塞式+函数式编程(Spring5必须让你使用java8)

  • Spring WebFlux是Spring 5.0引入的新的响应式框架,区别于Spring MVC,它不需要依赖Servlet API, 它是完全异步非阻塞的,并且基于Reactor来实现响应式流规范。

Gateway工作流程

三大核心概念

Route(路由)

  • 路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如断言为true则匹配该路由
Predicate(断言)
  • 参考的是Java8的java.util.function.Predicate,开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
Filter(过滤)
  • 指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改.
总结
  • web请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制,predicate就是我们的匹配条件:而filter. 就可以理解为一个无所不能的拦截器。有了这两个元素。再加上目标uri.就可以实现一个具体的路由了

官网总结

  • Clients make requests to Spring Cloud Gateway. If the Gateway Handler Mapping determines that a request matches a route, it is sent to the Gateway Web Handler. This handler runs the request through a filter chain that is specific to the request. The reason the filters are divided by the dotted line is that filters can run logic both before and after the proxy request is sent. All “pre” filter logic is executed. Then the proxy request is made. After the proxy request is made, the “post” filter logic is run.
  • 客户端向Spring Cloud Gateway发出请求。然后在Gateway Handler Mapping中找到与请求相匹配的路由,将其发送到Gateway Web Handler.Handler再通过指定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。
  • 过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前( “pre” )或之后( “post” )执行业务逻辑。
  • Filter在”pre” 类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,
  • 在”post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。

  • 核心逻辑: 路由转发+执行过滤器链

入门

  • Gateway网关路由有两种配置方式:
    • 在配置文件yaml中配置
    • 代码中注入RouteLocator的Bean

新建Module

  • 创建module: cloud-gateway-gateway9527

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <scope>runtime</scope>
    <optional>true</optional>
    </dependency>
  • YML

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    server:
    port: 9527
    spring:
    application:
    name: cloud-gateway-service
    eureka:
    instance:
    hostname: cloud_gateway_service
    client:
    service-url:
    defaultZone: http://127.0.0.1:7001/eureka/
    register-with-eureka: true
    fetch-registry: true
  • 主启动类

    1
    2
    3
    4
    5
    6
    7
    @SpringBootApplication
    @EnableEurekaClient
    public class GateWayMain9527 {
    public static void main(String[] args) {
    SpringApplication.run(GateWayMain9527.class,args);
    }
    }

路由映射(一)

  • 我们目前不想暴露8001端口,希望在8001外面套一层9527,网关如何做路由映射呢?

    1
    2
    3
    4
    5
    // 8001 的controller方法
    @GetMapping("/payment/lb/{id}")
    public String getPaymentLB(@PathVariable("id") Integer id) {
    return servicePort + "--> , id = " + id;
    }
  • YML新增网关配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    spring:
    application:
    name: cloud-gateway-service
    cloud:
    gateway:
    discovery:
    locator:
    enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
    routes:
    - id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名
    #匹配后提供服务的路由地址
    uri: http://localhost:8001
    predicates:
    - Path=/payment/lb/** # 断言,路径相匹配的进行路由

    测试

路由映射(二)

  • 官网案例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // GatewayConfig.java
    RemoteAddressResolver resolver = XForwardedRemoteAddressResolver
    .maxTrustedIndex(1);
    ...
    .route("direct-route",
    r -> r.remoteAddr("10.1.1.1", "10.10.1.1/24")
    .uri("https://downstream1")
    .route("proxied-route",
    r -> r.remoteAddr(resolver, "10.10.1.1", "10.10.1.1/24")
    .uri("https://downstream2")
    )
                百度国内新闻网站,需要外网
    
  • 自己写一个网关: 通过9527网关访问到外网的百度新闻网址

  • 业务实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Configuration
    public class GateWayConfig {
    /**
    * 配置了一个id为path_route的路由规则,|
    * 当访问地址http://localhost:9527/guonei时会自动转发到地址: http://news.baidu.com/guonei
    * @param builder
    * @return
    */
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    RouteLocatorBuilder.Builder routes = builder.routes();
    routes.route("path_route", r -> r.path("/guonei").uri("http://news.baidu.com/guonei"));
    return routes.build();
    }
    }

  • 测试

通过服务名实现动态

  • 默认情况下Gatway会根据注册中心注册的服务列表, 以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能

  • 启动:一个eureka7001+两个服务提供者8001/8002

  • YML

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    spring:
    application:
    name: cloud-gateway-service
    cloud:
    gateway:
    discovery:
    locator:
    enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
    routes:
    - id: payment_route # 路由的id,没有规定规则但要求唯一,建议配合服务名
    # 匹配后提供服务的路由地址
    - uri: http://localhost:8001
    + uri: lb://CLOUD-PROVIDER-HYSTRIX-PAYMENT
    predicates:
    - Path=/payment/lb/** # 断言,路径相匹配的进行路由
  • uri: lb://serverName是spring cloud gatway在微服务中自动为我们创建的负载均衡uri

路由配置的两种形式

  • 这些配置不能直接使用,需要和下面的Predicate配合使用才行。

路由到指定URL

  • 示例1:通配表示访问 GATEWAY_URL/** 会转发到 http://www.baidu.com/**

    1
    2
    3
    4
    5
    6
    spring:
    cloud:
    gateway:
    routes:
    - id: { 唯一标识 }
    uri: http://www.baidu.com
  • 示例2:精确匹配, 表示访问 GATEWAY_URL/spring/ 会转发到 http://www.baidu.com/spring/

    1
    2
    3
    4
    5
    6
    spring:
    cloud:
    gateway:
    routes:
    - id: { 唯一标识 }
    uri: http://www.baidu.com/spring/

路由到服务发现组件

  • 示例1:通配, 表示访问 GATEWAY_URL/** 会转发到 user-center 微服务的 /**

    1
    2
    3
    4
    5
    6
    spring:
    cloud:
    gateway:
    routes:
    - id: { 唯一标识 }
    uri: lb://user-center
  • 示例2:精确匹配, 表示访问 GATEWAY_URL/shares/1 会转发到 user-center 微服务的 /shares/1

    1
    2
    3
    4
    5
    6
    spring:
    cloud:
    gateway:
    routes:
    - id: { 唯一标识 }
    uri: lb://user-center/shares/1

Predicate

  • 启动我们的gateway9527

Route Predicate Factories

  • 官网说明

  • Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。Spring Cloud Gateway包括许多内置的Route PredicateI。所有这些Predicate都与HTTP请求的不同属性匹配。 多个RoutePredicate工厂可以逻辑and进行组合.

  • Spring Cloud Gateway创建Route对象时, 使用RoutePredicateFactory创建Predicate对象,Predicate对象可以赋值给Route。

  • Spring Cloud Gateway提供了十来种路由谓词工厂。为网关实现灵活的转发提供了基石。

    谓词工厂
    AfterRoutePredicateFactory 时间相关
    BeforeRoutePredicateFactory 时间相关
    BetweenRoutePredicateFactory 时间相关
    CookieRoutePredicateFactory Cookie相关
    HeaderRoutePredicateFactory Head相关
    HostRoutePredicateHostFactory Head相关
    MethodRoutePredicateFactory 请求相关
    PathRoutePredicateFactory 请求相关
    QueryRoutePredicateFactory 请求相关
    RemoteAddrRoutePredicateFactory 请求相关
    WeightRoutePredicateFactory 计算权重

After

  • TIPS

    • 技巧:时间可使用 System.out.println(ZonedDateTime.now()); 打印,然后即可看到时区。例如:2019-08-10T16:50:42.579+08:00[Asia/Shanghai]
    • 时间格式的相关逻辑:
      • 默认时间格式:org.springframework.format.support.DefaultFormattingConversionService#addDefaultFormatters
      • 时间格式注册:org.springframework.format.datetime.standard.DateTimeFormatterRegistrar#registerFormatters
  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    spring:
    cloud:
    gateway:
    routes:
    - id: after_route
    uri: lb://user-center
    predicates:
    # 当且仅当请求时的时间After配置的时间时,才会转发到用户微服务
    # 目前配置不会进该路由配置,所以返回404
    # 将时间改成 < now的时间,则访问localhost:8040/** -> user-center/**
    # eg. 访问http://localhost:8040/users/1 -> user-center/users/1
    - After=2030-01-20T17:42:47.789-07:00[America/Denver]

Before

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    spring:
    cloud:
    gateway:
    routes:
    - id: before_route
    uri: lb://user-center
    predicates:
    # 当且仅当请求时的时间Before配置的时间时,才会转发到用户微服务
    # 目前配置不会进该路由配置,所以返回404
    # 将时间改成 > now的时间,则访问localhost:8040/** -> user-center/**
    # eg. 访问http://localhost:8040/users/1 -> user-center/users/1
    - Before=2018-01-20T17:42:47.789-07:00[America/Denver]

Between

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    spring:
    cloud:
    gateway:
    routes:
    - id: between_route
    uri: lb://user-center
    predicates:
    # 当且仅当请求时的时间Between配置的时间时,才会转发到用户微服务
    # 因此,访问localhost:8040/** -> user-center/**
    # eg. 访问http://localhost:8040/users/1 -> user-center/users/1
    - Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2027-01-21T17:42:47.789-07:00[America/Denver]
  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    spring:
    cloud:
    gateway:
    routes:
    - id: cookie_route
    uri: lb://user-center
    predicates:
    # 当且仅当带有名为somecookie,并且值符合正则ch.p的Cookie时,才会转发到用户微服务
    # 如Cookie满足条件,则访问http://localhost:8040/** -> user-center/**
    # eg. 访问http://localhost:8040/users/1 -> user-center/users/1
    - Cookie=somecookie, ch.p
  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    spring:
    cloud:
    gateway:
    routes:
    - id: header_route
    uri: lb://user-center
    predicates:
    # 当且仅当带有名为X-Request-Id,并且值符合正则\d+的Header时,才会转发到用户微服务
    # 如Header满足条件,则访问http://localhost:8040/** -> user-center/**
    # eg. 访问http://localhost:8040/users/1 -> user-center/users/1
    - Header=X-Request-Id, \d+

Host

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    spring:
    cloud:
    gateway:
    routes:
    - id: host_route
    uri: lb://user-center
    predicates:
    # 当且仅当名为Host的Header符合**.somehost.org或**.anotherhost.org时,才会转发用户微服务
    # 如Host满足条件,则访问http://localhost:8040/** -> user-center/**
    # eg. 访问http://localhost:8040/users/1 -> user-center/users/1
    - Host=**.somehost.org,**.anotherhost.org

Method

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    spring:
    cloud:
    gateway:
    routes:
    - id: method_route
    uri: lb://user-center
    predicates:
    # 当且仅当HTTP请求方法是GET时,才会转发用户微服务
    # 如请求方法满足条件,访问http://localhost:8040/** -> user-center/**
    # eg. 访问http://localhost:8040/users/1 -> user-center/users/1
    - Method=GET

Path

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    spring:
    cloud:
    gateway:
    routes:
    - id: path_route
    uri: lb://user-center
    predicates:
    # 当且仅当访问路径是/users/*或者/some-path/**,才会转发用户微服务
    # segment是一个特殊的占位符,单层路径匹配
    # eg. 访问http://localhost:8040/users/1 -> user-center/users/1
    - Path=/users/{segment},/some-path/**,/red/{segment},/blue/{segment}
  • 官方文档,里面有个segment编程技巧。

    • 如果请求路径为:/users/zhangsan/red/blue/blue/green,则此路由匹配。

    • 该谓词会将URI模板变量(如定义的segment)提取为名称和值的映射,并使用 ServerWebExchangeUtils.URI_TEMPLATE_VARIABLES_ATTRIBUTE中定义的键将其放在ServerWebExchange.getAttributes()中。然后 GatewayFilter factories可以使用这些值。

    • 可以使用一个实用程序方法(称为get)来更容易地访问这些变量。下面的例子展示了如何使用get方法:

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

Query

  • 示例1:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    spring:
    cloud:
    gateway:
    routes:
    - id: query_route
    uri: lb://user-center
    predicates:
    # 当且仅当请求带有baz的参数,才会转发到用户微服务
    # eg. 访问http://localhost:8040/users/1?baz=xx -&gt; user-center的/users/1
    - Query=baz
  • 示例2:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    spring:
    cloud:
    gateway:
    routes:
    - id: query_route
    uri: lb://user-center
    predicates:
    # 当且仅当请求带有名为foo的参数,且参数值符合正则ba.,才会转发到用户微服务
    # eg. 访问http://localhost:8040/users/1?baz=baz -&gt; user-center的/users/1?baz=baz
    - Query=foo, ba.

RemoteAddr

  • 示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    spring:
    cloud:
    gateway:
    routes:
    - id: remoteaddr_route
    uri: lb://user-center
    predicates:
    # 当且仅当请求IP是192.168.1.1/24网段,例如192.168.1.10,才会转发到用户微服务
    # eg. 访问http://localhost:8040/users/1 -&gt; user-center的/users/1
    - RemoteAddr=192.168.1.1/24
  • 修改远程地址解析方式

    • 默认情况下,RemoteAddr路由谓词工厂使用来自传入请求的远程地址。如果Spring Cloud Gateway位于代理层之后,这可能与实际的客户端IP地址不匹配。

    • 您可以通过设置自定义的RemoteAddressResolver来自定义远程地址解析的方式。Spring Cloud Gateway带有一个非默认的远程地址解析器XForwardedRemoteAddressResolver,它基于X-Forwarded-For header

    • XForwardedRemoteAddressResolver有两个静态构造函数方法,它们采用不同的安全方法:

      • XForwardedRemoteAddressResolver返回一个RemoteAddressResolver,它总是接受在X-Forwarded-For报头中找到的第一个IP地址。这种方法很容易受到欺骗,因为恶意客户端可能会为X-Forwarded-For设置一个初始值,该值将被解析器接受。
    • XForwardedRemoteAddressResolver接受一个与Spring Cloud Gateway前面运行的可信基础设施数量相关的索引。例如,如果Spring Cloud Gateway只能通过HAProxy访问,那么应该使用值1。如果在访问Spring Cloud Gateway之前需要可信基础设施的两个跃点,那么应该使用值2。

    • 考虑以下头值:

      1
      X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3
      • 以下maxTrustedIndex值将生成以下远程地址:

        axTrustedIndex result
        [Integer.MIN_VALUE,0] (invalid, IllegalArgumentException during initialization)
        1 0.0.0.3
        2 0.0.0.2
        3 0.0.0.1
        [4, Integer.MAX_VALUE] 0.0.0.1

Weight

  • weight路由谓词工厂有两个参数:group和weight。每组计算权重。配置权重路由谓词的

  • 示例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    spring:
    cloud:
    gateway:
    routes:
    - id: weight_high
    uri: https://weighthigh.org
    predicates:
    # 80%的流量转发到weighthigh.org
    - Weight=group1, 8
    - id: weight_low
    uri: https://weightlow.org
    predicates:
    # 把~20%的流量转发到weighlow.org
    - Weight=group1, 2

Filter的使用

是什么

  • Route filters allow the modification of the incoming HTTP request or outgoing HTTP response in some manner. Route filters are scoped to a particular route. Spring Cloud Gateway includes many built-in GatewayFilter Factories.

  • 路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。

  • spring Cloud Gateway内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生。

  • 生命周期只有二种: pre和post

  • Filter种类只有二种:

常用的GatewayFilter

AddRequestParameter

  • 示例1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    spring:
    cloud:
    gateway:
    routes:
    - id: add_request_parameter_route
    uri: https://example.org
    filters:
    # 过滤工厂会在匹配的请求头加上一对请求头 red=blue
    - AddRequestParameter=red, blue
  • 示例2: AddRequestParameter。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    spring:
    cloud:
    gateway:
    routes:
    - id: add_request_parameter_route
    uri: https://example.org
    predicates:
    - Host: {segment}.myhost.org
    filters:
    # 过滤工厂知道用于匹配路径或主机的URI变量,变量可以在值中使用,并在运行时展开
    - AddRequestParameter=foo, bar-{segment}

自定义过滤器

全局GlobalFilter

  • 蛀牙是实现两个主要接口implments GlobalFilter,OrderId

  • 能干嘛

    • 全局日志记录
    • 统一网关鉴权
    • ….
  • 全局过滤器代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    @Component
    @Slf4j
    public class MyLogGatewayFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    log.info("come in global filter: {}", new Date());

    ServerHttpRequest request = exchange.getRequest();
    String uname = request.getQueryParams().getFirst("uname");
    if (uname == null) {
    log.info("用户名为null,非法用户");
    exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
    return exchange.getResponse().setComplete();
    }
    // 放行
    return chain.filter(exchange);
    }

    /**
    * 过滤器加载的顺序 越小,优先级别越高
    *
    * @return
    */
    @Override
    public int getOrder() {
    return 0;
    }
    }
  • 测试, 启动项目