Spring Cloud之-Gateway网关- 12(个人笔记)

1、概述简介

Gateway官方文档

Spring Cloud 1.x中,网关使用的是Zuul 1,在Spring Cloud 2.x中,网关使用的是Gateway,因为Zuul 2版本进展缓慢,所以Spring Cloud自己研发了网关,Gateway是原Zuul 1的替代版。Gateway采用异步非阻塞模型开发,性能上不需要担心,虽然Netflix发布了Zuul 2版本,但是Spring Cloud并没有整合的计划,所以才自己推出了Gateway的方案。

Spring Cloud GatewaySpring Cloud的一个全新项目,基于Spring 5+Spring Boot 2.x+Project Reactor等技术开发的网关,旨在为微服务架构提供一种简单有效的统一API路由管理方式

Spring Cloud Gateway作为Spring Cloud生态系统中的网关,目标是替代Zuul 1,在Spring Cloud 2.x版本中,没有对新版本Zuul 2最新高性能版本进行集成,仍然使用的Zuul 1非Reactor模式的老版本,为了提升网关性能,Spring Cloud Gateway是基于WebFlux框架实现的,而WebFlux框架底层使用了高性能的Reactor模式通信框架Netty
Spring Cloud之-Gateway网关- 12(个人笔记)_第1张图片


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

Spring Cloud Gateway网关的作用:反向代理鉴权流量控制熔断日志监控等。

在微服务架构中,网关的位置,位于各个微服务的上一层,通过网关后,就访问到了具体的微服务了
Spring Cloud之-Gateway网关- 12(个人笔记)_第2张图片

Spring Cloud之-Gateway网关- 12(个人笔记)_第3张图片

Spring Cloud Gateway特性:

  • 基于Spring Framework 5 + Project Reactor + Spring Boot 2.x进行构建
  • 动态路由:能够匹配任何请求属性
  • 支持路由指定Predicate(断言)和Filter(过滤器),而且编写容易
  • 集成了Hystrix断路器功能
  • 集成Spring Cloud服务发现功能
  • 支持请求限流功能
  • 支持路径重写功能

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

  • Zuul 1采用的是阻塞I/O的API网关
  • Zuul 1使用Servlet2.5的阻塞架构实现不支持任何长连接(如WebSocket)Zuul的设计模式和Nginx比较像,每次I/O都从工作线程中选择一个执行,请求线程在工作线程完成之前一直是阻塞的,Nginx是C++实现Zuul是Java实现JVM在第一次的加载时候,会比较慢,所以Zuul的性能比较差
  • Zuul 2设计理念跟先进,基于Netty非阻塞和支持长连接,但是目前Spring Cloud没有整合它Zuul 2的性能比Zuul 1性能有较大提升,Spring Cloud Gateway的性能也不错,官方测试数据表示,Spring Cloud Gateway的RPS(每秒请求数)是Zuul 1的1.6倍
  • Spring Cloud Gateway建立在Spring Framework 5 + Project Reactor + Spring Boot 2.x之上,使用非阻塞API
  • Spring Cloud Gateway还支持WebSocket,与Spring紧密集成拥有更好的开发体验

Zuul 1模型缺点:Zuul 1采用传统Servlet I/O处理模型,但请求进入servlet容器时,servlet容器会为其绑定一个线程,在并发不高的情况下是适用的,当并发量增加,线程数就会增加,但是线程资源是非常昂贵的(线程上下文切换内存消耗大),会影响到请求处理时间。有些简单的业务场景,并不需要每个请求分配一个线程,简单业务的高并发下,实际可能只需要几个线程就能扛得住,因此,每个请求分配一个线程,在高并发环境下并没有优势。

Gateway模型:Gateway模型采用的是WebFlux框架,这个框架是一个典型的非阻塞异步的框架,并且在Servlet 3.1后,支持了异步非阻塞,框架的核心是基于Reactor相关API实现的。相对于传统Web框架,它可以运行在支持Servlet 3.1容器上的组件中(如NettyUndertow等)。Spring WebFluxSpring 5引入的新的响应式框架,区别于Spring MVC,不需要依赖Servlet API,完全异步非阻塞,并且基于Reactor来实现响应式流规范。

Spring WebFlux参考官网

2、三大核心概念

2-1、Route(路由)

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

2-2、Predicate(断言)

参考Java8java.util.function.Predicate,开发人员可以匹配HTTP请求中的所有内容(比如请求头,请求参数等),如果请求与断言匹配,则进行路由

2-3、Filter(过滤)

类似于Web开发中的过滤器,这里指的是Spring框架中GatewayFilter实例,使用过滤器可以在请求被路由之前或之后对请求进行修改

总结:
路由的功能是由断言和过滤组合来实现的,一个Web请求发送后,先经过网关,网关里的断言和过滤用来判断这个请求是否需要路由转发,当断言为true,过滤器放行时候,这个请求进行路由转发,此时,请求才到达具体的微服务模块。

3、Gateway工作流程

Spring Cloud之-Gateway网关- 12(个人笔记)_第4张图片
客户端向Spring Cloud Gateway发送请求,然后在Gateway Handler Mapping中找到与请求相匹配的路由,将其Web HandlerHandler通过指定的过滤器链将请求发送到实际服务,执行业务逻辑,然后返回。如果有post类型的过滤器,执行过滤器逻辑。

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

post类型的过滤器可以做响应内容、响应头的修改、日志输出、流量监控等功能

4、入门配置

创建cloud-gateway-gateway9527模块,修改pom.xml,加入spring-cloud-starter-gatewayspring-cloud-starter-netflix-eureka-client的依赖。

cloud-gateway-gateway9527模块的pom.xml文件:


<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>cloud2020artifactId>
        <groupId>com.king.springcloudgroupId>
        <version>1.0-SNAPSHOTversion>
    parent>

    <modelVersion>4.0.0modelVersion>

    
    <artifactId>cloud-gateway-gateway9527artifactId>

    <dependencies>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-gatewayartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-devtoolsartifactId>
            <scope>runtimescope>
            <optional>trueoptional>
        dependency>
        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    dependencies>

project>

使用spring-cloud-starter-gateway依赖时不能添加spring-boot-starter-webspring-boot-starter-actuator依赖,不然会报错:

cloud-gateway-gateway9527模块的application.yml文件:

# 配置服务端口号
server:
  port: 9527

# 配置应用信息
spring:
  application:
    name: cloud-gateway # 配置应用名称

# 配置eureka
eureka:
  instance:
    hostname: cloud-gateway-service # 实例名称
  client:
    register-with-eureka: true # true:将自己注册进Eureka
    fetch-registry: true # true:需要去注册中心获取其他服务地址
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/ # 入驻的服务地址

cloud-gateway-gateway9527模块的主启动类:

package com.king.springcloud;

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

/**
 * 微服务网关模块主启动类
 * @EnableEurekaClient:表示是Eureka服务注册中心客户端
 */
@EnableEurekaClient
@SpringBootApplication
public class GatewayMain9527 {

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

cloud-gateway-gateway9527模块通过ymlGateway添加路由规则。

# 配置服务端口号
server:
  port: 9527

# 配置应用信息
spring:
  application:
    name: cloud-gateway # 配置应用名称
  cloud:
    # 配置spring gateway网关
    gateway:
      # 配置路由
      routes:
        # - 是yml语法,代表数组的意思
        - id: payment_route1 # 路由(名字)ID,没有固定规则,需要保证唯一
          uri: http://localhost:8001 # 路由到哪个地址,实际提供微服务的地址
          predicates:
            - Path=/payment/get/** # 路径匹配断言,**表示RESTFul请求的参数
        - id: payment_route2 # 路由(名字)ID,没有固定规则,需要保证唯一
          uri: http://localhost:8001 # 路由到哪个地址,实际提供微服务的地址
          predicates:
            - Path=/payment/loadBalance # 路径匹配断言

# 配置eureka
eureka:
  instance:
    hostname: cloud-gateway-service # 实例名称
  client:
    register-with-eureka: true # true:将自己注册进Eureka
    fetch-registry: true # true:需要去注册中心获取其他服务地址
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/ # 入驻的服务地址

相比之前的yml,这里的yml多了Gateway结点,配置这个的目的在于隐藏cloud-provider-payment8001模块的localhost:8001地址,如果想访问payment8001服务的/payment/get/**地址,之前需要访问http://localhost:8001/payment/get/1,配置了路由之后,访问http://localhost:9527/payment/get/1也可以实现,于是,原来的8001端口就隐藏了。

配置路由有两种方式,一种是上面的yml配置文件,另一种是是编码方式配置,uri中记得带http,否则访问不到,这里的uri可以写任意地址,代表一个路由规则,访问path路径的时候,被路由到uri地址。

cloud-gateway-gateway9527模块添加配置Gateway网关配置类:

package com.king.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;

/**
 * 编码方式配置Gateway网关
 */
@Configuration
public class GatewayConfig {
    /**
     * 配置路由
     * @param routeLocatorBuilder
     * @return
     */
    @Bean
    public RouteLocator routeLocator(RouteLocatorBuilder routeLocatorBuilder) {
        return routeLocatorBuilder.routes()
                // 当访问http://localhost:9527/payment/get/**的时候,请求会被路由到http://localhost:8001/payment/get/**
                .route("payment_route1", r -> r.path("/payment/get/**").uri("http://localhost:8001/payment/get/**"))
                // 当访问http://localhost:9527/payment/loadbalance的时候,请求会被路由到http://localhost:8001/payment/loadbalance
                .route("payment_route2", r -> r.path("/payment/loadbalance").uri("http://localhost:8001/payment/loadbalance"))
                .build();
    }
}

5、通过微服务名实现动态路由

现在存在的问题:真实服务地址写死了,我们应该通过服务名来找服务,而不是通过服务地址找服务。

Spring Cloud之-Gateway网关- 12(个人笔记)_第5张图片

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

为了演示网关的负载均衡,修改Provider8001Provider8002yml配置文件,将它们的注册地址改成eureka7001的地址。启动Eureka7001Provider8001Provider8002服务以及Gateway9527服务。修改Gateway9527模块的application.yml配置文件,修改为如下内容。因为要修改application.yml,所以先把GatewayConfig类进行屏蔽,避免产生影响。

cloud-gateway-gateway9527模块通过ymlGateway添加动态路由规则。

# 配置服务端口号
server:
  port: 9527

# 配置应用信息
spring:
  application:
    name: cloud-gateway # 配置应用名称
  cloud:
    # 配置spring gateway网关
    gateway:
      # 配置动态路由
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
      # 配置路由
      routes:
        # - 是yml语法,代表数组的意思
        - id: payment_route1 # 路由(名字)ID,没有固定规则,需要保证唯一
#          uri: http://localhost:8001 # 路由到哪个地址,实际提供微服务的地址
          uri: lb://cloud-provider-payment # 使用微服务应用名称查找路由地址,就是在Eureka注册中心里面的Application名称,lb是用于识别负载均衡的前缀,不能修改
          predicates:
            - Path=/payment/get/** # 路径匹配断言,**表示RESTFul请求的参数
        - id: payment_route2 # 路由(名字)ID,没有固定规则,需要保证唯一
#          uri: http://localhost:8001 # 路由到哪个地址,实际提供微服务的地址
          uri: lb://cloud-provider-payment # 使用微服务应用名称查找路由地址,就是在Eureka注册中心里面的Application名称,lb是用于识别负载均衡的前缀,不能修改
          predicates:
            - Path=/payment/loadBalance # 路径匹配断言

# 配置eureka
eureka:
  instance:
    hostname: cloud-gateway-service # 实例名称
  client:
    register-with-eureka: true # true:将自己注册进Eureka
    fetch-registry: true # true:需要去注册中心获取其他服务地址
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/ # 入驻的服务地址

通过浏览器访问http://localhost:9527/payment/loadBalance,在页面端可以看到端口号的不断变化,如果要实现负载均衡,注意uri中的lb是固定的,它是识别开启负载均衡的标志。

6、Predicate 断言的使用

Gateway9527启动的时候,在Console可以看到如下内容,代表执行加载Predicate,我们目前使用的PredicatePath

2021-10-05 20:38:06.989  INFO 10157 --- [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [After]
2021-10-05 20:38:06.989  INFO 10157 --- [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Before]
2021-10-05 20:38:06.989  INFO 10157 --- [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Between]
2021-10-05 20:38:06.989  INFO 10157 --- [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Cookie]
2021-10-05 20:38:06.989  INFO 10157 --- [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Header]
2021-10-05 20:38:06.989  INFO 10157 --- [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Host]
2021-10-05 20:38:06.989  INFO 10157 --- [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Method]
2021-10-05 20:38:06.989  INFO 10157 --- [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Path]
2021-10-05 20:38:06.989  INFO 10157 --- [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Query]
2021-10-05 20:38:06.989  INFO 10157 --- [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [ReadBodyPredicateFactory]
2021-10-05 20:38:06.989  INFO 10157 --- [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [RemoteAddr]
2021-10-05 20:38:06.989  INFO 10157 --- [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Weight]
2021-10-05 20:38:06.990  INFO 10157 --- [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [CloudFoundryRouteService]

官方文档:https://cloud.spring.io/spring-cloud-gateway/2.2.x/reference/html/#gateway-request-predicates-factories

Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。

Spring Cloud Gateway包括许多内置的Route Predicate Factory,这些Predicate HTTP请求的不同属性匹配,多个Route Predicate Factory可以进行组合。

Spring Cloud Gateway创建Route路由对象时,使用Route Predicate Factory创建Predicate对象,Predicate对象可以赋值给Route

根据官方文档里的说明,在application.yml里配置上即可生效,这相当于加了一个条件,条件满足就做路由转发,不满足就不路由转发。

简单说下吧,After Route PredicateBefore Route PredicateBetween Route Predicate需要用到一个DateTime值,这个值要使用ZonedDateTime类来获取。

cloud-gateway-gateway9527模块在测试包创建一个Test测试类:

import java.time.ZonedDateTime;

public class Test {

    public static void main(String[] args) {
        // 获取默认时区时间
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        System.out.println(zonedDateTime); // 2021-10-05T21:57:59.550+08:00[Asia/Shanghai]
    }
}

cloud-gateway-gateway9527模块使用After Route PredicateBefore Route PredicateBetween Route Predicate修改application.yml文件:

# 配置服务端口号
server:
  port: 9527

# 配置应用信息
spring:
  application:
    name: cloud-gateway # 配置应用名称
  cloud:
    # 配置spring gateway网关
    gateway:
      # 配置动态路由
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
      # 配置路由
      routes:
        # - 是yml语法,代表数组的意思
        - id: payment_route1 # 路由(名字)ID,没有固定规则,需要保证唯一
#          uri: http://localhost:8001 # 路由到哪个地址,实际提供微服务的地址
          uri: lb://cloud-provider-payment # 使用微服务应用名称查找路由地址,就是在Eureka注册中心里面的Application名称,lb是用于识别负载均衡的前缀,不能修改
          predicates:
            - Path=/payment/get/** # 路径匹配断言,**表示RESTFul请求的参数
        - id: payment_route2 # 路由(名字)ID,没有固定规则,需要保证唯一
#          uri: http://localhost:8001 # 路由到哪个地址,实际提供微服务的地址
          uri: lb://cloud-provider-payment # 使用微服务应用名称查找路由地址,就是在Eureka注册中心里面的Application名称,lb是用于识别负载均衡的前缀,不能修改
          predicates:
            - Path=/payment/loadBalance # 路径匹配断言
#            - Before=2021-10-05T21:57:59.550+08:00[Asia/Shanghai] # 在这个时间之前访问才有效
#            - After=2021-10-05T22:57:59.550+08:00[Asia/Shanghai] # 在这个时间之后访问才有效
            - Between=2021-10-05T21:57:59.550+08:00[Asia/Shanghai],2021-10-05T22:57:59.550+08:00[Asia/Shanghai] # 在这个区间时间才有效

# 配置eureka
eureka:
  instance:
    hostname: cloud-gateway-service # 实例名称
  client:
    register-with-eureka: true # true:将自己注册进Eureka
    fetch-registry: true # true:需要去注册中心获取其他服务地址
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/ # 入驻的服务地址

cloud-gateway-gateway9527模块使用Cookie Route Predicate 需要两个参数:一个是Cookie name,另外一个是正则表达式。Header Route Predicate 需要两个参数:一个属性名称,另外一个是正则表达式。Host Route Predicate的测试使用终端来测试,修改application.yml文件,通过发送curl命令即可完成,具体可以看一下curl命令的参数介绍,打开终端:

# 配置服务端口号
server:
  port: 9527

# 配置应用信息
spring:
  application:
    name: cloud-gateway # 配置应用名称
  cloud:
    # 配置spring gateway网关
    gateway:
      # 配置动态路由
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
      # 配置路由
      routes:
        # - 是yml语法,代表数组的意思
        - id: payment_route1 # 路由(名字)ID,没有固定规则,需要保证唯一
#          uri: http://localhost:8001 # 路由到哪个地址,实际提供微服务的地址
          uri: lb://cloud-provider-payment # 使用微服务应用名称查找路由地址,就是在Eureka注册中心里面的Application名称,lb是用于识别负载均衡的前缀,不能修改
          predicates:
            - Path=/payment/get/** # 路径匹配断言,**表示RESTFul请求的参数
        - id: payment_route2 # 路由(名字)ID,没有固定规则,需要保证唯一
#          uri: http://localhost:8001 # 路由到哪个地址,实际提供微服务的地址
          uri: lb://cloud-provider-payment # 使用微服务应用名称查找路由地址,就是在Eureka注册中心里面的Application名称,lb是用于识别负载均衡的前缀,不能修改
          # 配置断言
          predicates:
            - Path=/payment/loadBalance # 路径匹配断言
#            - Before=2021-10-05T21:57:59.550+08:00[Asia/Shanghai] # 在这个时间之前访问才有效
#            - After=2021-10-05T22:57:59.550+08:00[Asia/Shanghai] # 在这个时间之后访问才有效
#            - Between=2021-10-05T21:57:59.550+08:00[Asia/Shanghai],2021-10-05T22:16:59.550+08:00[Asia/Shanghai] # 在这个区间时间才有效
#            - Cookie=username,zhangsan # 请求中Cookie要有"username"键跟"zhangsan"值的数据才能有效访问
#            - Header=X-Request-id, \d+ # 请求头要有X-Request-id属性并且值为整数的正则表达式才能有效访问
            - Host=**.king.com # 请求中要加满足条件的Host才能有效访问

# 配置eureka
eureka:
  instance:
    hostname: cloud-gateway-service # 实例名称
  client:
    register-with-eureka: true # true:将自己注册进Eureka
    fetch-registry: true # true:需要去注册中心获取其他服务地址
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/ # 入驻的服务地址
#测试Cookie Route Predicate
test-MBP:~ test$ curl http://localhost:9527/payment/loadBalance --cookie "username=zhangsan"
8002
#测试Header Route Predicate
curl http://localhost:9527/payment/loadBalance -H "X-Request-Id:123"
8001
#测试Header Route Predicate
curl http://localhost:9527/payment/loadBalance -H "Host: www.king.com"
#测试Query Route Predicate
curl http://localhost:9527/payment/loadBalance -H "Host: 

cloud-gateway-gateway9527模块使用Method Route Predicate 是根据GETPOST做断言,Path Route Predicate就是我们最初使用的方式,Query Route Predicate是根据请求里所带Query参数进行判断的,RemoteAddr Route Predicate是对请求发起ip做的校验,Weight Route Predicate是给负载均衡分配权重的,可以指定请求发到某一个uri的权重。

# 配置服务端口号
server:
  port: 9527

# 配置应用信息
spring:
  application:
    name: cloud-gateway # 配置应用名称
  cloud:
    # 配置spring gateway网关
    gateway:
      # 配置动态路由
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
      # 配置路由
      routes:
        # - 是yml语法,代表数组的意思
        - id: payment_route1 # 路由(名字)ID,没有固定规则,需要保证唯一
#          uri: http://localhost:8001 # 路由到哪个地址,实际提供微服务的地址
          uri: lb://cloud-provider-payment # 使用微服务应用名称查找路由地址,就是在Eureka注册中心里面的Application名称,lb是用于识别负载均衡的前缀,不能修改
          predicates:
            - Path=/payment/get/** # 路径匹配断言,**表示RESTFul请求的参数
        - id: payment_route2 # 路由(名字)ID,没有固定规则,需要保证唯一
#          uri: http://localhost:8001 # 路由到哪个地址,实际提供微服务的地址
          uri: lb://cloud-provider-payment # 使用微服务应用名称查找路由地址,就是在Eureka注册中心里面的Application名称,lb是用于识别负载均衡的前缀,不能修改
          # 配置断言
          predicates:
            - Path=/payment/loadBalance # 路径匹配断言
            - Method=GET,POST # 请求方式是GET或POST才能有效访问
            - Query=username, \d+ # 要有参数名username并且值一定要整数才能有效访问

# 配置eureka
eureka:
  instance:
    hostname: cloud-gateway-service # 实例名称
  client:
    register-with-eureka: true # true:将自己注册进Eureka
    fetch-registry: true # true:需要去注册中心获取其他服务地址
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/ # 入驻的服务地址
#测试Path Route Predicate
curl http://localhost:9527/payment/loadBalance
#测试Method Route Predicate
curl http://localhost:9527/payment/loadBalance
#测试Query Route Predicate
curl http://localhost:9527/payment/loadBalance?username=31

所以说,Predicate可以提供一组匹配规则,每当一个请求过来的时候,去检验这些规则,如果满足规则,进行路由,否则,就提示出错。

7、Filter的使用

路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用,Spring Cloud Gateway内置了多种路由过滤器,它们是通过Gateway Filter Factory产生的。

生命周期来分类,可以分为两种Pre 业务逻辑之前Post 业务逻辑之后,类似于Spring AOP的前置通知和后置通知。从种类上来分类,可以分为两种Gateway Filter 单一的Global Filter 全局的。具体可以参考官网,这个的配置也是在application.yml里加配置即可。

Gateway Filter:官网使用参考文档
下面就是写一个简单的Gateway Filter配置,其他的就可以参照上面的官方文档进行配置:

# 配置服务端口号
server:
  port: 9527

# 配置应用信息
spring:
  application:
    name: cloud-gateway # 配置应用名称
  cloud:
    # 配置spring gateway网关
    gateway:
      # 配置动态路由
      discovery:
        locator:
          enabled: true # 开启从注册中心动态创建路由的功能,利用微服务名称进行路由
      # 配置路由
      routes:
        # - 是yml语法,代表数组的意思
        - id: payment_route1 # 路由(名字)ID,没有固定规则,需要保证唯一
#          uri: http://localhost:8001 # 路由到哪个地址,实际提供微服务的地址
          uri: lb://cloud-provider-payment # 使用微服务应用名称查找路由地址,就是在Eureka注册中心里面的Application名称,lb是用于识别负载均衡的前缀,不能修改
          predicates:
            - Path=/payment/get/** # 路径匹配断言,**表示RESTFul请求的参数
        - id: payment_route2 # 路由(名字)ID,没有固定规则,需要保证唯一
#          uri: http://localhost:8001 # 路由到哪个地址,实际提供微服务的地址
          uri: lb://cloud-provider-payment # 使用微服务应用名称查找路由地址,就是在Eureka注册中心里面的Application名称,lb是用于识别负载均衡的前缀,不能修改
#         # 配置Gateway Filter
          filters:
            - AddRequestParameter=X-Request-id,1024 # 过滤器工厂会在匹配的请求头加上一对请求头,名称为X-Request-id,值为1024才能有效访问
          # 配置断言
          predicates:
            - Path=/payment/loadBalance # 路径匹配断言
            - Method=GET,POST # 请求方式是GET或POST才能有效访问
            - Query=username, \d+ # 要有参数名username并且值一定要整数才能有效访问

# 配置eureka
eureka:
  instance:
    hostname: cloud-gateway-service # 实例名称
  client:
    register-with-eureka: true # true:将自己注册进Eureka
    fetch-registry: true # true:需要去注册中心获取其他服务地址
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/ # 入驻的服务地址

Global Filter:官网使用参考文档
下面来介绍Global Filter自定义全局过滤器,我们可以根据业务需求做定制化处理。

package com.king.springcloud.filter;

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.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 首先自定义全局过滤器要实现两个接口:GlobalFilter、Ordered
 *
 * 能做"全局日志记录"、"统一网关鉴权"等等的业务功能。
 */
@Component
public class MyGatewayFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取Request,获取参数
        MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
        System.out.println(queryParams);
        // 这里可以对queryParams里的值做一些校验
        if ("".equals(queryParams.getFirst("username"))) {
            System.out.println("非法用户");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            // 表示该请求已经处理完成
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }

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

你可能感兴趣的:(SpringCloud,spring,cloud)