Gateway新一代网关

Gateway新一代网关

1、概述

上一代的网关zuul地址:https://github.com/Netflix/zuul/wiki

新一代网关的地址:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/

Gateway是在Spring生态系统之上构建的API网关服务,基于Spring 5,Spring Boot 2和 Project Reactor等技术。

Gateway旨在提供一种简单而有效的方式来对API进行路由,以及提供一些强大的过滤器功能, 例如:熔断、限流、重试等

SpringCloud Gateway 是 Spring Cloud 的一个全新项目,基于 Spring 5.0+Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4v5S4MQm-1666137143414)(image/59、网关.png)]

2、我们为什么选择Gateway?

2.1、neflix不太靠谱,zuul2.0一直跳票,迟迟不发布

一方面因为Zuul1.0已经进入了维护阶段,而且Gateway是SpringCloud团队研发的,是亲儿子产品,值得信赖。而且很多功能Zuul都没有用起来也非常的简单便捷。

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

多方面综合考虑Gateway是很理想的网关选择。

2.2、SpringCloud Gateway具有如下特性

Spring Cloud Gateway 具有如下特性:

基于Spring Framework 5, Project Reactor 和 Spring Boot 2.0 进行构建;

动态路由:能够匹配任何请求属性;

可以对路由指定 Predicate(断言)和 Filter(过滤器);

集成Hystrix的断路器功能;

集成 Spring Cloud 服务发现功能;

易于编写的 Predicate(断言)和 Filter(过滤器);

请求限流功能;

支持路径重写。

2.3、SpringCloud Gateway 与 Zuul的区别

Spring Cloud Gateway 与 Zuul的区别在SpringCloud Finchley 正式版之前,Spring Cloud 推荐的网关是 Netflix 提供的Zuul:

1、Zuul 1.x,是一个基于阻塞 I/ O 的 API Gateway

2、Zuul 1.x 基于Servlet 2. 5使用阻塞架构它不支持任何长连接(如 WebSocket) Zuul 的设计模式和Nginx较像,每次 I/ O 操作都是从工作线程中选择一个执行,请求线程被阻塞到工作线程完成,但是差别是Nginx 用C++ 实现,Zuul 用 Java 实现,而 JVM 本身会有第一次加载较慢的情况,使得Zuul 的性能相对较差。

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

4、Spring Cloud Gateway 建立 在 Spring Framework 5、 Project Reactor 和 Spring Boot 2 之上, 使用非阻塞 API。

5、Spring Cloud Gateway 还 支持 WebSocket, 并且与Spring紧密集成拥有更好的开发体验

2.4、Zuul1.x模型

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

==Servlet的生命周期?==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模型的弊端

2.5、GateWay模型

Reactive官网地址:https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-new-framework

传统的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 来实现响应式流规范。

3、三大核心概念

3.1、Route(路由)

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

3.2、Predicate(断言)

参考的是Java8的java.util.function.Predicate开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配(是否有该请求路径)则进行路由转发

3.3、Filter(过滤)

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

3.4、总结

web请求,通过一些匹配条件,定位到真正的服务节点。并在这个转发过程的前后,进行一些精细化控制。predicate就是我们的匹配条件;而filter,就可以理解为一个无所不能的拦截器。有了这两个元素,再加上目标uri,就可以实现一个具体的路由了

4、Gateway工作流程【路由转发+执行过滤器链】

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Hqlsdir5-1666137143415)(image/60、gateway工作流程.png)]

客户端向Spring云网关发起请求。如果网关处理程序映射确定一个请求与路由匹配,它就被发送到网关Web处理程序。该处理程序通过特定于请求的筛选链运行请求。用虚线分隔过滤器的原因是,过滤器可以在发送代理请求之前和之后运行逻辑。执行所有“预”过滤器逻辑。然后发出代理请求。在发出代理请求之后,将运行“post”过滤器逻辑。

Filter在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,

“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。

5、Gateway入门配置

5.1、新建网关模块cloud-gateway-gateway9527

5.2、导入pom.xml文件

主要的还是spring-cloud-starter-gateway网关的依赖文件

<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.zcl.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>
依赖注意:因为Gateway是一个网关服务是不需要任何的web相关的依赖的,如果配置了如下依赖启动会出现错误,所以依赖里面不能有如下依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TIPDVLIP-1666137143415)(image/61、网关启动失败.png)]

5.3、配置YAML配置文件

server:
  port: 9527

spring:
  application:
    name: cloud-gateway

eureka:
  instance:
    hostname: cloud-gateway-service
  client: #服务提供者provider注册进eureka服务列表内
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka # 配置单机版的Eureka

5.4、创建主动类

注意:网关自身也是一个微服务

package com.zcl.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * 描述:网关启动类
 *
 * @author zhong
 * @date 2022-09-20 13:38
 */
@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
    public static void main(String[] args) {
        SpringApplication.run(GateWayMain9527.class, args);
    }
}

5.5、新增网关配置

下面的地址是对cloud-provider-payment8001提供者模块的getlb控制器接口进行配置,不想暴露8001端口,希望通过9527网关进行拦截

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh # 路由的ID,没有固定规则但要求唯一,建议配合服务名称
          uri: http://localhost:8001 # 匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/** # 断言。路由匹配,与uil拼接一起形成完整的请求路径
        - id: payment_routh2 # 路由的ID,没有固定规则但要求唯一,建议配合服务名称
          uri: http://localhost:8001 # 匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/** # 断言。路由匹配,与uil拼接一起形成完整的请求路劲

5.6、启动测试

  1. 启动7001Eureka服务注册中心

  2. 启动8001服务提供者微服务

  3. 启动9527微服务

  4. 查看Eureka服务中心

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rUiOfO4q-1666137143416)(image/62、检测Eureka.png)]

  5. 通过8001的原访问地址测试

    http://localhost:8001/payment/get/1
    
    http://localhost:8001/payment/lb
    

    原地址测试正常再测试下面的网关请求地址测试

  6. 通过添加网关服务后转发请求8001信息

    http://localhost:9527/payment/get/1
    
    http://localhost:9527/payment/lb
    

5.7、网关配置的两种方式

1、YML配置文件(详情看5.3步骤)

官网配置地址:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#configuration

2、在代码中注入RouteLocator的Bean

官方java代码实现案例:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#configuration

// static imports from GatewayFilters and RoutePredicates
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder, ThrottleGatewayFilterFactory throttle) {
    return builder.routes()
            .route(r -> r.host("**.abc.org").and().path("/image/png")
                .filters(f ->
                        f.addResponseHeader("X-TestHeader", "foobar"))
                .uri("http://httpbin.org:80")
            )
            .route(r -> r.path("/image/webp")
                .filters(f ->
                        f.addResponseHeader("X-AnotherHeader", "baz"))
                .uri("http://httpbin.org:80")
                .metadata("key", "value")
            )
            .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();
}

模拟官网实现Java实现网关配置

注意:设置的path路径是拼接在uri后面的,如果不匹配就会导致断言为false导致请求转发不到

package com.zcl.springcloud.config;

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 描述:java编码配置网关信息
 *
 * @author zhong
 * @date 2022-09-20 14:39
 */
@Configuration
public class GateWayConfig {

    /**
     * 配置了一个id为route-name的路由规则,
     * 当访问地址 http://localhost:9527/guonei时会自动转发到地址:http://news.baidu.com/guonei
     * @param builder
     * @return
     */
    @Bean
    public RouteLocator customRouteLocator2(RouteLocatorBuilder builder)
    {
        RouteLocatorBuilder.Builder routes = builder.routes();

        routes.route("path_route_atguigu", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();

        return routes.build();

    }

    /**
     * 配置路由信息,当访问当前网关的http://localhost:9527/就会转发到http://xiaozhong01.top这个地址
     * 目前的配置只能转发到http协议的
     * @param routeLocatorBuilder
     * @return
     */
    @Bean
    public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
        // 创建对象对象
        RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
        // 配置路由信息
        routes.route("diaokebiji_xiaozhong01", r -> r.path("/").uri("https://xiaozhong01.top")).build();
        return routes.build();
    }
}

6、通过微服务名实现动态路由(Route)

通过上面的入门配置网关可以看出,我们的配置都是写死的8001,如果后面对于服务的扩容不是很友好,而我们的服务都是注册到服务中心的有一个微服务名称,微服务下可以有多个不同的服务和端口,下面就是要实现动态的实现网关路由。

在没有使用网关之前的编码都是通过Ribbon实现负载均衡调用微服务下的服务,现在有了网关之后通过对外只暴露网关的接口,待网关完成三大核心(路由、断言、过滤)之后负载均衡的调用各服务接口

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

6.1、添加Eureka客户端依赖

 <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

6.2、修改pom.xml配置文件

需要注意的是uri的协议为lb,表示启用Gateway的负载均衡功能。

lb://serviceName是spring cloud gateway在微服务中自动为我们创建的负载均衡uri(动态)

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh # 路由的ID,没有固定规则但要求唯一,建议配合服`务每次
          # uri: http://localhost:8001 # 匹配后提供服务的路由地址
          uri: lb://CLOUD-PAYMENT-SERVICE # 匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/** # 断言。路由匹配的进行路由,与uii拼接一起形成完整的请求路劲
        - id: payment_routh2 # 路由的ID,没有固定规则但要求唯一,建议配合服务每次
          # uri: http://localhost:8001 # 匹配后提供服务的路由地址
          uri: lb://CLOUD-PAYMENT-SERVICE # 匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/** # 断言。路由匹配的进行路由,与uii拼接一起形成完整的请求路劲

6.3、启动项目测试

  1. 启动7001Eureka服务注册中心
  2. 启动8001、8002服务提供者
  3. 启动9517网关服务
  4. 访问http://localhost:9527/payment/lb网关地址,查看是否有8001、8002两个端口切换的情况

7、Predicate(断言)的使用

官方地址:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3Jntx6bs-1666137143417)(image/63、Route Predicate Factories.png)]

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

Spring Cloud Gateway 创建 Route 对象时, 使用 RoutePredicateFactory 创建 Predicate 对象,Predicate 对象可以赋值给 Route。 Spring Cloud Gateway 包含许多内置的Route Predicate Factories。

所有这些谓词都匹配HTTP请求的不同属性。多种谓词工厂可以组合,并通过逻辑and。

7.1、常用的Route Predicate配置YAML

下面的代码都是在

spring:
  cloud:
    gateway:
      routes:
          predicates: # 在断言里面下

7.1.1、After Route Predicate

After路由谓词工厂接受一个参数,即datetime(这是java的ZonedDateTime)。此谓词匹配发生在指定datetime之后的请求。配置after路由谓词的示例如下:

如果不按照指定的时间之后进行访问网关地址就会报错404 NOT_FOUND

- Path=/payment/lb/** # 断言。路由匹配的进行路由,与uii拼接一起形成完整的请求路劲
- 2022-09-20T18:10:32.695+08:00[Asia/Shanghai] # 指定时间之后访问网关才起效

对于上面的时间生成是如何的呢,通过下面的代码执行生成即可

import java.time.ZonedDateTime;

/**
 * 描述:测试
 *
 * @author zhong
 * @date 2022-09-20 18:09
 */
public class test1 {
    public static void main(String[] args) {
        ZonedDateTime now = ZonedDateTime.now();
        System.out.println(now);
        // 2022-09-20T18:10:32.695+08:00[Asia/Shanghai]
    }
}

7.1.2、Before Route Predicate

Before路由谓词工厂有一个参数,一个datetime(这是一个java的ZonedDateTime)。此谓词匹配发生在指定datetime之前的请求。配置before路由谓词的示例如下:

- Before=2022-09-20T18:10:32.695+08:00[Asia/Shanghai] # - Before= 在什么之前

7.1.3、Between Route Predicate

Between路由谓词工厂有两个参数,datetime1和datetime2,它们是java ZonedDateTime对象。此谓词匹配发生在datetime1之后和datetime2之前的请求。参数datetime2必须在datetime1之后。下面的示例配置between路由谓词:

- Between=2022-09-20T18:10:32.695+08:00[Asia/Shanghai], 2022-09-20T18:20:32.695+08:00[Asia/Shanghai] # - Between= 在什么中间

7.1.4、Cookie Route Predicate

Cookie路由谓词工厂接受两个参数,Cookie名称和regexp(这是一个Java正则表达式)。此谓词匹配具有给定名称且其值与正则表达式匹配的cookie。配置一个cookie路由谓词工厂的示例如下:

- Cookie=cookice的Key, value

使用CURL进行携带cookie的测试,打开电脑的终端进行测试

  1. 不携带cookie

    C:\Users\zhong>curl http://localhost:9527/payment/lb
    
  2. 携带cookie

    C:\Users\zhong>curl http://localhost:9527/payment/lb --cookie "username=zzzyyy"
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MxBLtfrb-1666137143417)(image/64、CURL请求cookice.png)]

7.1.5、Header Route Predicate

Header路由谓词工厂接受两个参数,头和regexp(这是一个Java正则表达式)。该谓词与具有指定名称且其值与正则表达式匹配的标头进行匹配。配置头路由谓词的示例如下:

- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式

使用CURL进行携带cookie的测试,打开电脑的终端进行测试

  1. 不携带请求头

    C:\Users\zhong>curl http://localhost:9527/payment/lb
    
  2. 携带请求头

    C:\Users\zhong>curl http://localhost:9527/payment/lb -H "X-Request-Id:123"
    

7.1.6、Host Route Predicate

Host Route Predicate 接收一组参数,一组匹配的域名列表,这个模板是一个 ant 分隔的模板,用.号作为分隔符。它通过参数中的主机地址作为匹配规则

- Host=**.xiaozhong.com

使用CURL进行携带cookie的测试,打开电脑的终端进行测试

  1. 不携带域名列表

    curl http://localhost:9527/payment/lb
    
  2. 携带域名列表

    curl http://localhost:9527/payment/lb -H "Host: www.xiaozhong.com" 
    

7.1.7、Method Route Predicate

方法路由谓词工厂接受一个方法参数,它是一个或多个参数:要匹配的HTTP方法。下面的例子配置了一个方法路由谓词:

- Method=GET,POST

7.1.8、Path Route Predicate

Path Route Predicate Factory接受两个参数:一个Spring PathMatcher模式列表和一个名为matchTrailingSlash(默认为true)的可选标志。下面的示例配置一个路径路由谓词:

- Path=/red/{segment},/blue/{segment}

7.1.9、Query Route Predicate

Query路由谓词工厂接受两个参数:一个必需的参数和一个可选的regexp(这是一个Java正则表达式)。配置查询路由谓词的示例如下:

- Query=username, \d+  # 要有参数名username并且值还要是整数才能路由
  1. 请求

    http://localhost:9527/payment/lb?username=31
    

7.2.0、小结

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名进行路由
      routes:
        - id: payment_routh # 路由的ID,没有固定规则但要求唯一,建议配合服`务每次
          # uri: http://localhost:8001 # 匹配后提供服务的路由地址
          uri: lb://CLOUD-PAYMENT-SERVICE # 匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/** # 断言。路由匹配的进行路由,与uii拼接一起形成完整的请求路劲
        - id: payment_routh2 # 路由的ID,没有固定规则但要求唯一,建议配合服务每次
          # uri: http://localhost:8001 # 匹配后提供服务的路由地址
          uri: lb://CLOUD-PAYMENT-SERVICE # 匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/** # 断言。路由匹配的进行路由,与uii拼接一起形成完整的请求路劲
            - After=2022-09-20T18:10:32.695+08:00[Asia/Shanghai] # - After= 在什么之后,指定时间之后访问网关才起效
            # - Before=2022-09-21T19:10:32.695+08:00[Asia/Shanghai] # - Before= 在什么之前
            # - Between=2022-09-20T18:10:32.695+08:00[Asia/Shanghai], 2022-09-21T19:30:32.695+08:00[Asia/Shanghai] # - Between= 在什么中间
            # - Cookie=username, zzzyyy # 携带cookie断言
            # - Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式
            # - Host=**.xiaozhong.com
            - Method=GET,POST
            - Query=username, \d+  # 要有参数名username并且值还要是整数才能路由

# id:我们自定义的路由 ID,保持唯一
# uri:目标服务地址
# predicates:路由条件,Predicate接受一个输入参数返回一个布尔值。
# 该属性包含多种默认方法来将Predicate组合成其他复杂的逻辑(比如:与,或,非)

8、Filter(过滤)的使用

路由过滤器允许在某种程度上修改传入的HTTP请求或传出HTTP响应。路由过滤器只能指定路由进行使用

Spring Cloud Gateway包括许多内置的网关过滤器工厂。

8.1、GatewayFilter

官方地址:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#global-filters

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uj0n0DsZ-1666137143418)(image/65、GatewayFilter.png)]

使用案例

根据官网的案例赋值粘贴修改即可

spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        - AddRequestHeader=X-Request-red, blue

8.2、GlobalFilter

官方地址:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#global-filters

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7uuksHex-1666137143418)(image/66、全局过滤器.png)]

8.3、自定义全局过滤器【重点】

需要实现implements GlobalFilter,Ordered两个主要的接口

作用:

  1. 全局日记记录
  2. 统一网关鉴权
  3. ….

8.3.1、定义全局日记配置过滤器

package com.zcl.springcloud.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;

/**
 * 描述:全局日记过滤器
 *
 * @author zhong
 * @date 2022-09-20 19:55
 */
@Slf4j
@Component
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("---------- 进去全局过滤方法 MyLogGateWayFilter: "+new Date());
        // 请求必须携带指定的用户名信息
        String username = exchange.getRequest().getQueryParams().getFirst("username");
        if(username == null){
            log.info("---------- 请求的用户名不能为空!");
            // 赋值响应的状态码
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        // 合法过滤,进入下一个过滤链
        return chain.filter(exchange);
    }

    /**
     * 加载过滤器的优先顺序,值越小权重越高
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

8.3.2、启动测试

  1. 访问携带参数的地址

    http://localhost:9527/payment/lb?username=zhangsan
    
  2. 访问不携带参数的地址

    http://localhost:9527/payment/lb
    

    如果没有携带,或者没有正确的携带username都会直接拦截,不让访问。

    不同于predicates断言,断言如果不符合还会返回报错信息,而过浏览拦截不过的只有空白页面(后面也可以配置)

  • 39
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 26
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小钟要学习!!!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值