新一代网关 Spring Cloud Gateway

  • 一、什么是 Gateway
  • 二、能干啥
  • 三、微服务架构中网关在哪里
  • 四、为什么选择 Gateway
  • 五、Gateway 与 Zuul 的区别(技术选型)
  • Zuul 1.x 的模型
  • Gateway 的模型
  • 六、网关中的三大核心概念
  • 1、Route(路由)
  • 2、Predicate(断言)
  • 3、Filter(过滤)
  • 七、Gateway 网关的工作流程
  • 八、如何搭建一个简单的 Gateway 网关微服务模块
  • 路由转发的两种实现方式:
  • 十、常用的九种类型 Predicate 断言的配置实现
  • 十一、Gateway 的 Filter 过滤器
  • 1、什么是 Gateway 中的 Filter 过滤器
  • 2、Gateway 的 Filter 的分类
  • 3、Filter 的生命周期
  • 4、自定义过滤器


一、什么是 Gateway

官网:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/

Spring Cloud Gateway 使用的 WebFlux 中的 Reactor-Netty 响应式编程软件,底层使用了 Netty 通讯框架。

二、能干啥

反向代理、流量控制、熔断、日志监控、权限控制等等

三、微服务架构中网关在哪里

springcloud 绕过网关 springcloud网关原理_gateway

即简单的来说,网关是微服务系统的统一入口。

四、为什么选择 Gateway

① 因为 Zuul1.0 已经进入了维护阶段,而且 Gateway 是 SpringCloud 团队研发的,并且很多功能 Zuul 也没有用起来, Gateway 相较于 Zuul 更简单便捷。

② Gateway 是基于异步非阻塞模型上进行开发的,性能方面不需要担心。虽然 Netflix 早就发布了最新的 Zuul 2.x,
但 Spring Cloud 貌似没有整合计划。而且Netflix相关组件都宣布进入维护期。

所以综合考虑 Gateway 是很理想的网关选择。

同时,Spring Cloud Gateway 具有如下特性:

  • 动态路由:能够匹配任何请求属性;
  • 可以对路由指定 Predicate(断言)和 Filter(过滤器);
  • 集成Hystrix的断路器功能;
  • 集成 Spring Cloud 服务发现功能;
  • 易于编写的 Predicate(断言)和 Filter(过滤器);
  • 请求限流功能;
  • 支持路径重写。

五、Gateway 与 Zuul 的区别(技术选型)

Zuul 1.x 的模型

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

Servlet 是由 Servlet Container 进行生命周期管理:

  • container启动时构造servlet对象并调用servlet init()进行初始化;
  • container运行时接受请求,并为每个请求分配一个线程(一般从线程池中获取空闲线程)然后调用service();
  • container关闭时调用servlet destory()销毁servlet。

springcloud 绕过网关 springcloud网关原理_spring cloud_02

该模式的缺点:

servlet 是一个简单的网络 IO 模型,当请求进入servlet container 时,servlet container 就会为其绑定一个线程,在并发不高的场景下这种模型是适用的。但是一旦高并发(比如用 jemeter 高压测试),线程数量就会上涨,而线程资源代价是昂贵的(上下文切换,内存消耗大)严重影响请求的处理时间。在一些简单业务场景下,不希望为每个request分配一个线程,只需要1个或几个线程就能应对极大并发的请求,这种业务场景下servlet模型没有优势。

所以 Zuul 1.X 是基于 servlet 之上的一个阻塞式处理模型,即 spring 实现了处理所有 request 请求的一个 servlet(DispatcherServlet)并由该servlet阻塞式处理处理。所以 Spring Cloud Zuul 无法摆脱 servlet 模型的弊端。

所以:

在 SpringCloud Finchley 正式版之前,Spring Cloud 推荐的网关是 Netflix 提供的Zuul:Zuul 1.x,是一个基于阻塞 I/ O 的 API Gateway(网关);同时Zuul 1.x 基于Servlet 2. 5使用阻塞架构不支持任何长连接(如 WebSocket) Zuul 的设计模式和Nginx较像,每次 I/ O 操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但是差别是Nginx 用C++ 实现,Zuul 用 Java 实现,而 JVM 本身会有第一次加载较慢的情况,使得Zuul 的性能相对较差。

虽然 Zuul 2.x 理念更先进,想基于Netty非阻塞和支持长连接,但 Spring Cloud 目前还没有整合。 Zuul 2.x 的性能较 Zuul 1.x 有较大提升。在性能方面,根据官方提供的基准测试, Spring Cloud Gateway 的 RPS(每秒请求数)是Zuul 的 1. 6 倍。

Gateway 的模型

Spring Cloud Gateway 建立 在 Spring Framework 5、 Project Reactor 和 Spring Boot 2 之上, 使用 非阻塞 API。同时,Spring Cloud Gateway 还 支持 WebSocket, 并且与Spring紧密集成拥有更好的开发体验。

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

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

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

Spring WebFux 官网:https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#spring-webflux

六、网关中的三大核心概念

1、Route(路由)

路由是构建网关的基本模块,它又 ID、目标 URI,一系列的断言和过滤器组成, 如果断言为 true 则匹配该路由。

2、Predicate(断言)

参考的:Java 8 的 java.util.function.Predicate 接口

开发人员可以通过断言匹配 HTTP 请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由转发。

3、Filter(过滤)

指的是 Spring 框架中 Gateway Filter 的实例,使用过滤器,可以在请求被路由前或后对请求进行修改。

七、Gateway 网关的工作流程

springcloud 绕过网关 springcloud网关原理_java_03

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 网关微服务模块

1)创建 cloud-gateway-gateway9527 模块

2)在 pom.xml 文件中添加以下依赖

<dependencies>
    <!--gateway-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <!--eureka-client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
    <dependency>
        <groupId>com.tianfei.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>
    <!--一般基础配置类-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

3)配置 application.yml 文件

server:
  port: 9527

spring:
  application:
    name: cloud-gateway
    
eureka:
  instance:
    hostname: cloud-gateway-service
  client:
    register-with-eureka: true
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # eureka 注册中心集群的地址

4)编写主启动类

/**
 * @Author Herz
 * @Date 2022/1/13 15:58
 */
@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
    public static void main(String[] args) {
        SpringApplication.run(GateWayMain9527.class, args);
    }
}

5)如何实现针对于服务提供者的 Controller 路径分别为 http://localhost:8001/payment/lbhttp://localhost:8001/payment/get/{id} 的路由以及断言 即 不暴露 8001 端口通过暴露 9527 端口来访问 服务提供者 的服务

路由转发的两种实现方式:

  • 在 Gateway 微服务模块的 yml 文件中配置如下内容(推荐):
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001          # 匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001          # 匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由

测试:分别访问 端口 8001 的 服务提供者的请求 http://localhost:8001/payment/lbhttp://localhost:8001/payment/get/1

再测试通过 Gateway 网关通过路由转发访问 服务提供者 的服务,请求地址分别为 http://localhost:9527/payment/lbhttp://localhost:9527/payment/get/1

  • 编写一个配置类 GateWayConfig
/**
 * @Author Herz
 * @Date 2022/1/14 10:08
 */
@Configuration
public class GateWayConfig {

    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();

        routes.route("route_path"
                 // r.path 的参数就是访问 Gateway 的请求路径(即断言,路径相匹配的进行路由)
                ,r -> r.path("/payment/lb/**")
                        // uri:匹配后提供服务的路由地址
                        .uri("http://localhost:8001/payment/lb")).build();

        routes.route("route_path"
                ,r -> r.path("/payment/get/**")
                        .uri("http://localhost:8001/payment/get/**")).build();

        return routes.build();
    }
}

#九、GateWay 怎样实现动态路由(主要以 yml 文件的形式实现)

在 yml 中配置以下内容:

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由

      routes:
        - id: payment_routh # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由

十、常用的九种类型 Predicate 断言的配置实现

  • After Route Rredicate
  • 作用:当前访问路径如果匹配断言的路径并且在指定的时间之后访问,则给该请求进行路由转发
  • 配置实现:在 yml 文件中做以下配置
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由

      routes:
        - id: payment_routh # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
            - After=2022-01-14T11:55:54.737+08:00[Asia/Shanghai]         # after 断言,路径相匹配的进行路由

当前系统时间可通过 ZonedDateTime.now() 方法获取:

/**
 * @Author Herz
 * @Date 2022/1/14 11:55
 */
public class T2 {
    public static void main(String[] args) {
        ZonedDateTime time = ZonedDateTime.now();

        System.out.println(time);
        // 2022-01-14T13:50:46.666+08:00[Asia/Shanghai]
    }
}
  • Before Route Rredicate
  • 作用:当前访问路径如果匹配断言的路径并且在指定的时间之前访问,则给该请求进行路由转发
  • 配置实现:在 yml 做以下配置
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由

      routes:
        - id: payment_routh # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
            - After=2022-01-14T11:55:54.737+08:00[Asia/Shanghai]         # after 断言,路径相匹配的进行路由
            - Before=2022-03-14T11:55:54.737+08:00[Asia/Shanghai]         # before 断言,路径相匹配的进行路由
  • Between Route Rredicate
  • 作用:当前访问路径如果匹配断言的路径并且在指定的某段时间之间访问,则给该请求进行路由转发
  • 配置实现:yml 配置文件中做以下配置
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由

      routes:
        - id: payment_routh # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
            - Between=2022-01-14T11:55:54.737+08:00[Asia/Shanghai],2022-03-14T11:55:54.737+08:00[Asia/Shanghai]   # between 断言,路径相匹配的进行路由
  • Cookie Route Rredicate
  • Cookie Route Predicate 需要两个参数,一个是 Cookie name ,一个是正则表达式。
  • 作用:当前访问路径如果匹配断言的路径并且路由规则会通过获取对应的 Cookie name 值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行。
  • 配置实现:yml 配置如下
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由

      routes:
        - id: payment_routh # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
            - Cookie=username,tianfei     # cookie 断言,路径相匹配的进行路由
  • 使用 curl 命令进行测试:curl http://localhost:9527/payment/lb --cookie "username=tianfei"curl http://localhost:9527/payment/get/1 --cookie "username=tianfei"返回的中文乱码,可以参考
  • Header Route Rredicate
  • 两个参数:一个是属性名称和一个正则表达式,这个属性值和正则表达式匹配则执行。
  • 配置实现:在 yml 文件中配置以下内容
server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由

      routes:
        - id: payment_routh # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
            - Header=X-Request-Id, \d+  # 请求头要有 X-Request-Id 属性并且值为整数的正则表达式
  • curl 命令测试:curl http://localhost:9527/payment/lb -H "X-Request-Id:1"

springcloud 绕过网关 springcloud网关原理_spring_04

  • Host Route Rredicate
  • Host Route Predicate 接收一组参数,一组匹配的域名列表,它通过参数中的主机地址作为匹配规则。
  • 配置实现:在yml配置文件中做以下配置
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由

      routes:
        - id: payment_routh # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
            - Host=**.tianfei.com         # 只要所附带的主机地址满足 .tianfei.com 则进行路由
  • curl 命令测试:curl http://localhost:9527/payment/lb -H "Host:www.tianfei.com"
  • Method Route Rredicate
  • 参数为 POST 或 GET,表示请求的类型
  • 配置实现:在 yml 文件中做以下配置
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由

      routes:
        - id: payment_routh # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
            - Method=GET                  # 当请求是 GET 类型的请求时,进行路由
  • curl 命令测试:curl http://localhost:9527/payment/lbcurl -X -POST http://localhost:9527/payment/lb
  • Path Route Rredicate
  • Path Route Predicate 接收一组参数,一组请求地址列表,它通过请求地址作为匹配规则。
  • 实现配置如下:
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由

      routes:
        - id: payment_routh # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
  • Query Route Rredicate
  • 支持传入两个参数,一个是属性名,一个为属性值,属性值可以是正则表达式。
  • 具体 yml 配置如下下:
spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由

      routes:
        - id: payment_routh # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 # payment_route    # 路由的ID,没有固定规则但要求唯一,建议配合服务名
          # uri: http://localhost:8001          # 匹配后提供服务的路由地址
          uri: lb://cloud-provider-payment # 匹配后提供服务的路由地址,lb:uri 的协议为 lb,表示启用 Gateway 的负载均衡功能
                                           # lb:serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由
            - Query=userId, \d+  # 要有参数名 userId 并且值还要是整数才能路由
  • curl 命令测试:curl http://localhost:9527/payment/lb?userId=1

十一、Gateway 的 Filter 过滤器

官网:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gatewayfilter-factories

1、什么是 Gateway 中的 Filter 过滤器

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

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

2、Gateway 的 Filter 的分类

  • GatewayFilter
  • GlobalFilter

3、Filter 的生命周期

  • pre
  • post

4、自定义过滤器

只需要编写一个类,实现 GlobalFilter、Ordered两个接口并实现其方法

/**
 * 
 * 自定义过滤器
 * 
 * @Author Herz
 * @Date 2022/1/14 15:33
 */
@Component
@Slf4j
public class MyLogGateWayGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        log.info("***********come in MyLogGateWayGlobalFilter: "+ new Date());
        // 获取第一个名为 uname 的参数值
        String uname = exchange.getRequest().getQueryParams().getFirst("uname");

        if (uname == null){
            log.info("*********用户名为 null,非法用户。o(╥﹏╥)o");
            // 设置响应码
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }

        // 如果 uname 不为 null,则执行后面的 filter 过滤链
        return chain.filter(exchange);
    }

    /**
     * 用来排序的方法
     * @return 返回的值越小排在越前面
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

测试:在浏览器中输入地址:http://localhost:9527/payment/lb?uname=11

springcloud 绕过网关 springcloud网关原理_gateway_05

http://localhost:9527/payment/lb?unameasd=11

springcloud 绕过网关 springcloud网关原理_gateway_06