四、服务网关


一、Zuul 路由网关


1. 是什么

  • Zuul 是一种提供 动态路由、监视、弹性、安全性 等功能的边缘服务。
  • Zuul 是 Netflix 出品的一个基于JVM 路由 和 服务端 的负载均衡器。
  • API 网关 为微服务架构中的服务提供了 统一的访问入口,客户端通过 API 网关访问相关服务。
  • API 网关的定义类似于设计模式中的门面模式,它相当于整个微服务架构中的门面,所有客户端的访问都通过它来进行路由及过滤。
  • 它实现了 请求路由、负载均衡、校验过滤、服务容错、服务聚合 等功能。
  • Zuul 包含了如下最主要的功能:代理 + 路由 + 过滤 三大功能。
    在这里插入图片描述
    在这里插入图片描述

2. 能干嘛

  • 由于 Zuul 自动集成了 Ribbon 和 Hystrix。
    所以 Zuul 天生就有 负载均衡服务容错 的能力。

2.1 路由

2.2 过滤

2.3 负载均衡
  • 网关为入口,由 网关 与 微服务 进行交互,所以网关必须要实现 负载均衡 的功能。
  • 网关会获取 微服务注册中心 里面的服务连接地址,再配合一些算法选择其中一个服务地址,进行处理业务。
  • 这个属于 客户端的负载均衡,由调用方去实现负载均衡逻辑。
    在这里插入图片描述

2.4 灰度发布(又称金丝雀发布)
  • 起源是,矿井工人发现金丝雀对瓦斯气体很敏感,矿工会在下井之前,先放一只金丝雀到井中,如果金丝雀不叫了,就代表瓦斯浓度高。
    在这里插入图片描述
  • 在灰度发布开始后,先启动一个新版本应用,但是并不直接将流量切过来,而是测试人员对新版本进行线上测试,启动的这个新版本应用,就是我们的金丝雀。
  1. 如果没有问题,那么可以将少量的用户流量导入到新版本上,然后再对新版本做运行状态观察,收集各种运行时数据,如果此时对新旧版本做各种数据对比,就是所谓的 A/B 测试。
  2. 新版本没什么问题,那么逐步扩大范围、流量,把所有用户都迁移到新版本上面来。

3. 路由基本配置

  • 功能:路由功能负责将 外部请求 转发到 具体的服务实例 上去,是实现统一访问入口的基础。

3.1 新建 Module cloud-gateway-zuul9527

3.2 POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-2020</artifactId>
        <groupId>com.qs.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-gateway-zuul9527</artifactId>

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

        <!--actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </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>

</project>

3.3 YML
  • 修改 hosts 文件。
# 添加映射配置
127.0.0.1 zuul9527.com

server:
  port: 9527

spring:
  application:
    name: cloud-gateway-zuul

eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka
  instance:
    instance-id: zuul9527.com
    prefer-ip-address: true

3.4 主启动
@SpringBootApplication
@EnableZuulProxy
public class ZuulMain9527 {

    public static void main(String[] args) {
        SpringApplication.run(ZuulMain9527.class, args);
    }
}

3.5 测试

4. 路由访问映射规则


4.1 配置代理名称
  • 修改 YML
zuul:
  # 路由映射配置(代理名称)
  routes:
    # 代理名称
    mypayment.path: /provider/**
    # 对应服务id
    mypayment.serviceId: provider-payment-service
    # 可以配置多个
    mysms.path: /sms/**
    mysms.serviceId: cloud-provider-sms

4.2 忽略原有真实服务名
  • 修改 YML
zuul:
  # 忽略原有真实服务名
#  ignored-services: provider-payment-service
  # 多个可以用 "*"
  ignored-services: "*"

4.3 路由转发 和 负载均衡 功能

4.3.1 新建 Module cloud-provider-sms8008

4.3.2 POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-2020</artifactId>
        <groupId>com.qs.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-provider-sms8008</artifactId>

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

        <!--web + actuator-->
        <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>

        <!--热部署-->
        <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>

</project>

4.3.3 YML
server:
  port: 8008

# 服务名称(服务注册到Eureka名称)
spring:
  application:
    name: cloud-provider-sms

# 服务提供者cloud-provider-sms注册进Eureka服务列表内
eureka:
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

4.3.4 主启动
@SpringBootApplication
@EnableEurekaClient
public class SMSMain8008 {

    public static void main(String[] args) {
        SpringApplication.run(SMSMain8008.class, args);
    }
}

4.3.5 SMSController
@RestController
public class SMSController {

    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/sms")
    public String sms() {
        return "sms: " + serverPort;
    }
}

4.3.6 测试

http://zuul9527.com:9527/provider/payment/get/1 负载均衡(8001/8002)
http://zuul9527.com:9527/sms/sms 路由转发(8008)


5. 设置统一公共前缀


5.1 修改 YML
zuul:
  # 设置统一公共前缀
  prefix: /qs

5.2 测试

http://zuul9527.com:9527/qs/provider/payment/get/1
http://zuul9527.com:9527/qs/sms/sms


6. 查看路由信息


6.1 修改 POM
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

6.2 YML
# 开启查看路由的端点
management:
  endpoints:
    web:
      exposure:
        include: 'routes' 

6.3 测试

http://localhost:9527/actuator/routes


7. 过滤器

  • 过滤 功能负责对请求过程进行额外的处理,是 请求校验过滤 及 服务聚合 的基础。
  • 过滤器的生命周期。
    在这里插入图片描述

7.1 ZuulFilter
  • 过滤类型。
  1. pre:在请求 被 路由到目标服务 前执行。
    比如:权限校验、打印日志等功能。
  2. routing:在请求 被 路由到目标服务 时执行。
  3. post:在请求 被 路由到目标服务 后执行。
    比如:给目标服务的响应添加头信息,收集统计数据等功能。
  4. error:请求在其他阶段 发生错误 时执行。

  • 过滤顺序。
    数字小的先执行。

  • 过滤是否开启。
    shouldFilter 方法为 true。

7.2 配置前置过滤器——打印日志
  • 前置过滤器,用于在请求路由到 目标服务 前打印请求日志。

7.2.1 PreLogFilter
@Component
@Slf4j
public class PreLogFilter extends ZuulFilter {

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

	/**
     * 在调用之前会打印日志
     */
    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String host = request.getRemoteHost();
        String method = request.getMethod();
        String uri = request.getRequestURI();
        log.info("host: {}, method: {}, uri: {}, date: {}", host, method, uri, new Date().getTime());
        return null;
    }
}

7.2.2 YML
zuul:
  # 过滤器开关 
  PreLogFilter:
    pre:
      disable: false

7.2.3 测试

http://localhost:9527/qs/sms/sms


二、Gatewa 新一代网关


1. 是什么

  • Cloud 全家桶中有个很重要的组件就是网关,在 1.x 版本中都是采用的 Zuul 网关。
  • 但在 2.x 版本中,Zuul 的升级一直跳票,Spring Cloud 最后自己研发了一个网关替代 Zuul,那就是 Spring Cloud Gateway 一句话:Gateway 是原 Zuul1.x 版的替代
    在这里插入图片描述
  • Gateway 是在 Spring 生态系统之上构建的 API 网关服务,基于 Spring-5.0,Spring Boot-2.0 和 Project Reactor 等技术。
  • Gateway 旨在提供一种简单而有效的方式来对 API 进行路由,以及提供一些强大的过滤器功能。
    例如:熔断、限流、重试 等。

  • Spring Cloud Gateway 是 Spring Cloud 的一个全新项目,基于 Spring-5.0,Spring Boot-2.0 和 Project Reactor 等技术开发的网关。
    它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式。
  • Spring Cloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul。
    在 Spring Cloud-2.0 以上版本中,没有对新版本的 Zuul-2.0 以上最新高性能版本进行集成,仍然还是使用的 Zuul-1.x 非 Reactor 模式的老版本。
    而为了提升网关的性能,Spring Cloud Gateway 是基于 WebFlux 框架实现的,而 WebFlux 框架底层则使用了高性能的 Reactor 模式通信框架 Netty
  • Spring Cloud Gateway 的目标提供统一的路由方式且基于 Filter 链 的方式提供了网关基本的功能。
    例如:安全,监控/指标,和限流
  • 一句话:Spring Cloud Gateway 使用的 WebFlux 中的 reactor-netty 响应式编程组件,底层使用了 Netty 通讯框架。

2. 能干嘛

2.1 反向代理
2.2 鉴权
2.3 流量控制
2.4 熔断
2.5 日志监控

3. 微服务架构中网关在哪里

在这里插入图片描述


4. 有了 Zuul 怎么又出来了 Gateway


4.1 我们为什么选择 Gateway
  • Neflix 不太靠谱,Zuul-2.0 一直跳票,迟迟不发布。
  1. 一方面因为 Zuul-1.0 已经进入了维护阶段,而且 Gateway 是 Spring Cloud 团队研发的,是亲儿子产品,值得信赖。
    而且很多功能 Zuul 都没有,用起来也非常的简单便捷。
  2. Gateway 是基于 异步非阻塞模型上 进行开发的,性能方面不需要担心。
    虽然 Netflix 早就发布了最新的 Zuul-2.x,但 Spring Cloud 貌似没有整合计划。
    而且 Netflix 相关组件都宣布进入维护期;不知前景如何?
  3. 多方面综合考虑 Gateway 是很理想的网关选择。

  • Spring Cloud Gateway 具有如下特性。
  1. 基于 Spring Framework-5.0,Project Reactor 和 Spring Boot-2.0 进行构建。
  2. 动态路由:能够匹配任何请求属性。
  3. 可以对路由指定 Predicate(断言)和 Filter(过滤器)
  4. 集成 Hystrix 的断路器功能。
  5. 集成 Spring Cloud 服务发现功能。
  6. 易于编写的 Predicate(断言)和 Filter(过滤器)。
  7. 请求限流功能。
  8. 支持路径重写。

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

4.2 Zuul-1.x 模型
  • Spring Cloud 中所集成的 Zuul 版本,采用的是 Tomcat 容器。
    使用的是传统的 Servlet IO 处理模型。

  • Servlet 的生命周期?
  1. Servlet 由 Servlet Container 进行生命周期管理。
  2. Container 启动时,构造 Servlet 对象并调用 Servlet.init() 进行初始化。
  3. Container 运行时,接受请求并为每个请求分配一个线程(一般从线程池中获取空闲线程)然后调用 service()
  4. Container 关闭时,调用 Servlet.destory() 销毁 Servlet。

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

4.3 Gateway 模型
  1. 传统的 Web 框架,比如说:Struts2,SpringMVC 等都是基于 Servlet API 与 Servlet 容器基础之上运行的。
  2. 但是 在 Servlet-3.1 之后有了 异步非阻塞 的支持
    而 WebFlux 是一个典型 异步非阻塞 的框架,它的核心是基于 Reactor 的相关 API 实现的。
    相对于传统的 Web 框架来说,它可以运行在诸如 Netty,Undertow 及支持 Servlet-3.1 的容器上。
    非阻塞式 + 函数式编程(Spring-5.0 必须让你使用 Java-8)。
  3. Spring WebFlux 是 Spring-5.0 引入的新的响应式框架,区别于 Spring MVC。
    它不需要依赖 Servlet API,它是完全异步非阻塞的,并且基于 Reactor 来实现响应式流规范。

5. 三大核心概念


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

5.2 Predicate(断言)
  • 参考的是 Java-8 的 java.util.function.Predicate,开发人员可以匹配 HTTP 请求中的所有内容(例如:请求头 或 请求参数),如果请求与 断言 相匹配则进行路由

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

5.4 Route + Predicate + Filter
  • Web 请求通过一些匹配条件,定位到真正的服务节点。
    并在这个转发过程的前后,进行一些精细化控制。
  1. Predicate 就是我们的匹配条件。
  2. 而 Filter 就可以理解为一个无所不能的拦截器。
  • 有了这两个元素,再加上目标 URI,就可以实现一个具体的路由了。
    在这里插入图片描述

6. Gateway 工作流程

  • 客户端向 Spring Cloud Gateway 发出请求。
    然后在 Gateway Handler Mapping 中找到与请求 相匹配的路由,将其发送到 Gateway Web Handler。
  • Handler 再通过指定的过滤器链,来将请求发送到我们实际的服务执行业务逻辑,然后返回。
  • 过滤器之间用虚线分开,是因为过滤器可能会在发送代理请求之前(pre)或之后(post)执行业务逻辑。
  1. Filter 在 “pre” 类型的过滤器可以做 参数校验、权限校验、流量监控、日志输出、协议转换 等。
  2. 在 “post” 类型的过滤器中可以做 响应内容、响应头的修改,日志的输出,流量监控等有着非常重要的作用。
  • 核心逻辑:路由转发 + 执行过滤器链
    在这里插入图片描述

7. 入门配置


7.1 新建 Module cloud-gateway-gateway9527

7.2 POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud-2020</artifactId>
        <groupId>com.qs.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-gateway-gateway9527</artifactId>

    <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通用包-->
        <dependency>
            <groupId>com.qs.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>

</project>

7.3 YML
server:
  port: 9527

spring:
  application:
    name: cloud-gateway-gateway

  cloud:
   # 配置Gateway
    gateway:
    
      # 一、路由
      routes:
        # payment_route 路由的id,没有固定规则,但要求唯一,建议配合服务名
        - id: payment_routh
          # uri 目标服务地址,匹配后提供服务的路由地址
          uri: http://localhost:8001
          predicates:
            # 断言,路径相匹配的进行路由
            - Path=/payment/get/**
        
        - id: payment_routh2 
          uri: http://localhost:8001
          predicates:
            - Path=/payment/lb/**
            
eureka:
  instance:
    hostname: cloud-gateway-gateway
  client:
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

7.4 主启动
@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {

    public static void main(String[] args) {
        SpringApplication.run(GateWayMain9527.class, args);
    }
}

7.5 测试

http://localhost:8001/payment/lb 添加网关前
http://localhost:9527/payment/lb 添加网关后


8. Gateway 网关路由有两种配置方式


8.1 YML 配置(参考上面)

8.2 代码中注入 RouteLocatorBean
@Configuration
public class GateWayConfig {

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

    }

    @Bean
    public RouteLocator customRouteLocator2(RouteLocatorBuilder builder) {
        RouteLocatorBuilder.Builder routes = builder.routes();
        routes.route("path_route_guoji", r -> r.path("/guoji").uri("http://news.baidu.com/guoji")).build();
        return routes.build();
    }
}

8.3 测试

http://localhost:9527/guonei
http://localhost:9527/guoji


9. 通过 微服务名 实现动态路由

  • 默认情况下 Gateway 会根据注册中心注册的服务列表,以注册中心上 微服务名 为路径创建 动态路由进行转发,从而实现动态路由的功能
  • 需要注意的是 uri 的协议为 lb,表示启用 Gateway 的负载均衡功能。
  • lb://serviceName 是 Spring Cloud Gateway 在微服务中自动为我们创建的负载均衡 uri。

9.1 修改 YML
spring:
  cloud:
    # 配置Gateway
    gateway:
    
      # 通过微服务名实现动态路由
      discovery:
        locator:
          # true 表示开启从注册中心动态创建路由的功能,利用微服务名进行路由
          enabled: true
          
      # 一、路由
      routes:
        - id: payment_routh2
#          uri: http://localhost:8001
          # lb://serviceName是 Spring Cloud Gateway在微服务中自动为我们创建的负载均衡uri
          uri: lb://provider-payment-service
          predicates:
            - Path=/payment/lb/**          

9.2 测试

http://localhost:9527/payment/lb 8001/8002两个端口切换


10. Predicate 的使用


10.1 是什么
  • 启动我们的 gateway9527
    在这里插入图片描述

10.2 Route Predicate Factories 这个是什么?
  • 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。
    在这里插入图片描述

10.3 常用的 Route Predicate

在这里插入图片描述


10.3.1 After Route Predicate

在这里插入图片描述

predicates:
  # 1. 在某个时间之后可访问
  - After=2021-08-28T19:49:32.007+08:00[Asia/Shanghai]

  • 我们的问题是:上述这个After好懂,这个时间串串?
// 默认时区
ZonedDateTime zbj = ZonedDateTime.now(); 
// 指定时区获取当前时间
ZonedDateTime zny = ZonedDateTime.now(ZoneId.of("America/New_York")); 

10.3.2 Before Route Predicate

在这里插入图片描述

predicates:
  # 2. 在某个时间之前可路由
  - Before=2021-08-29T19:49:32.007+08:00[Asia/Shanghai]	

10.3.3 Between Route Predicate
predicates:
  # 3. 在某个时间段之间可路由
  - Between=2021-08-28T19:49:32.007+08:00[Asia/Shanghai],2021-08-29T19:49:32.007+08:00[Asia/Shanghai]

10.3.4 Cookie Route Predicate
  • Cookie Route Predicate 需要两个参数,一个是 Cookie name,一个是正则表达式。
  • 路由规则会通过获取对应的 Cookie name 值 和 正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行。
    在这里插入图片描述
predicates:
  # 4. 携带--cookie "username=zzyy"可路由
  - Cookie=username,zzyy

  1. 不带 Cookie 访问。
    curl http://localhost:9527/payment/lb
    在这里插入图片描述

  1. 带上 Cookie 访问。
    加入curl返回中文乱码
    curl http://localhost:9527/payment/lb --cookie "username=zzyy"
    在这里插入图片描述

10.3.5 Header Route Predicate
  • 两个参数:一个是属性名称 和 一个正则表达式,这个 属性值 和 正则表达式 匹配则执行。
    在这里插入图片描述
predicates:
  # 5. 请求头要有X-Request-Id属性,并且值为正数的正则表达式可路由
  - Header=X-Request-Id, \d+	

curl http://localhost:9527/payment/lb -H "X-Request-Id:123"
在这里插入图片描述


10.3.6 Host Route Predicate
  • Host Route Predicate 接收一组参数,一组匹配的域名列表,这个模板是一个 ant 分隔的模板,用 . 号作为分隔符。
  • 它通过参数中的 主机地址 作为匹配规则。
    在这里插入图片描述
predicates:
  # 6. 请求头要有Host属性,并且.qs.com结尾可路由
  - Host=**.qs.com

curl http://localhost:9527/payment/lb -H "Host: www.qs.com" 正确
curl http://localhost:9527/payment/lb -H "Host: java.qs.com" 正确
curl http://localhost:9527/payment/lb -H "Host: java.qs.net" 错误
在这里插入图片描述


10.3.7 Method Route Predicate

在这里插入图片描述

predicates:
  # 7. 限制为GET请求可路由
  - Method=GET

在这里插入图片描述


10.3.8 Path Route Predicate

在这里插入图片描述

predicates:
  # 8. 匹配路径的进行路由
  - Path=/payment/lb/**

10.3.9 Query Route Predicate

支持传入两个参数,一个是属性名,一个为属性值,属性值可以是正则表达式。
在这里插入图片描述

predicates:
  # 9. 要有参数名username,并且值为正数可路由
  - Query=username, \d+	

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


10.3.10 断言 All 配置
  • 说白了,Predicate 就是为了实现一组匹配规则,让请求过来找到对应的 Route 进行处理。
# 二、断言`All`配置  
# predicates 路由条件,接受一个输入参数返回一个布尔值,该属性包含多种默认方法来将 Predicate组合成其他复杂的逻辑(比如:与、或、非) 
predicates:
  # 1. 在某个时间之后可路由
#  - After=2021-08-28T19:49:32.007+08:00[Asia/Shanghai]
  # 2. 在某个时间之前可路由
#  - Before=2021-08-29T19:49:32.007+08:00[Asia/Shanghai]
  # 3. 在某个时间段之间可路由
  - Between=2021-08-28T19:49:32.007+08:00[Asia/Shanghai],2021-08-29T19:49:32.007+08:00[Asia/Shanghai]
  # 4. 携带--cookie "username=zzyy"可路由
  - Cookie=username,zzyy
  # 5. 请求头要有X-Request-Id属性,并且值为正数的正则表达式可路由
  - Header=X-Request-Id, \d+
  # 6. 请求头要有Host属性,并且.qs.com结尾可路由
  - Host=**.qs.com
  # 7. 限制为GET请求可路由
  - Method=GET
  # 8. 匹配路径的进行路由
  - Path=/payment/lb/**
  # 9. 要有参数名username,并且值为正数可路由
  - Query=username, \d+

11. Filter 的使用


11.1 是什么
  • 路由过滤器可用于修改进入的 HTTP 请求 和 返回的 HTTP 响应,路由过滤器只能指定路由进行使用。
  • Spring Cloud Gateway 内置了多种路由过滤器,他们都由 Gateway Filter 的工厂类来产生。
    在这里插入图片描述

11.2 Spring Cloud Gateway 的 Filter
  • 生命周期。
  1. pre 前置。
  2. post 后置。

  • 种类。
  1. GatewayFilter(31 种)单一
    https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#the-addrequestparameter-gatewayfilter-factory
  2. GlobalFilter(10 种)全局
    在这里插入图片描述

11.3 常用的 Gateway Filter
  • AddRequestParameter。
spring:
  cloud:
    # 配置Gateway
    gateway:
 
      # 通过微服务名实现动态路由
      discovery:
        locator:
          # true 表示开启从注册中心动态创建路由的功能,利用微服务名进行路由
          enabled: true
          # 使用小写服务名,默认是大写
          lower-case-service-id: true
          
      routes:
        - id: payment_routh1
          uri: lb://provider-payment-service      
          predicates:
            - Path=/paymentInfo/**        
            - Method=GET,POST
            
          # 三、过滤器(GatewayFilter31 + GlobalFilter10)
          filters:
            # GatewayFilter > AddRequestParameter,过滤器工厂会在匹配的请求头加上一对请求头,名称为`X-Request-Id`值为`1024`
            - AddRequestParameter=X-Request-Id,1024

11.4 自定义全局过滤器
  • 全局日志记录。
  • 统一网关鉴权。
@Component
public class MyLogGateWayFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        System.out.println("time:" + new Date() + ",执行了自定义的全局过滤器:" + "MyLogGateWayFilter");

        String uname = exchange.getRequest().getQueryParams().getFirst("uname");
        if (uname == null) {
            System.out.println("用户名为空");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }
        // 放行
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
    	// 数字越小,优先级越高
        return 0;
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

骑士梦

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

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

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

打赏作者

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

抵扣说明:

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

余额充值