一、简介

Spring Cloud Gateway 是 Spring 官方基于 Spring 5.x,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,旨在为微服务架构提供一种简单而有效的统一的 API 路由管理方式,目标是替代 Netflix Zuul,底层是Netty网络编程框架-ServerSocket,其不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,可用于服务安全,统一服务入口管理,负载均衡,限流,鉴权

二、快速入门

需求:通过网关作为服务访问入口,对系统中的服务进行访问,例如通过网关服务去访问sca-provider服务.
第一步:创建sca-gateway模块(创建springboot项目,这里不详细介绍啦),然后pom文件加网关依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

第二步:yml文件中添加相关配置

server:
  port: 9000
spring:
  application:
    name: msa-gateway
  cloud:
    gateway:
      routes: #配置网关路由规则
        - id: route01  #路由id,自己指定一个唯一值即可
          uri: http://localhost:8082 # 网关帮我们转发的url,即访问provider 只能一个实例,不能负载均衡
          predicates: #匹配请求规则 断言(谓词)
            - Path=/nacos/provider/echo/**  #请求路径定义,此路径对应uri中的资源
          filters: #网关过滤器,对谓词中的内容进行判断分析及处理
            - StripPrefix=1 #转发之前去掉path中的第一层路径,例如nacos

# 开发阶段打开gateway日志
logging:
  level:
    org.springframework.cloud.gateway: debug

其中:路由(routes) 是 gateway 中最基本的组件之一,表示一个具体的路由信息载体。主要定义了下面的几个信息:

  • id,路由标识符,区别于其他 Route
  • uri,路由指向的目的地 uri,即客户端请求最终被转发到的微服务
  • predicate,断言(谓词)的作用是进行条件判断,只有断言都返回真,才会执行路由。
  • filter,过滤器用于修改请求和响应信息

第三步:依次启动sca-provider,sca-gateway服务,然后打开浏览器,进行访问测试,
在这里插入图片描述

三、负载均衡实现

网关才是服务访问的入口,所有服务都会在网关层面进行底层映射,所以在访问服务时,要基于服务serivce id(服务名)去查找对应的服务,让请求从网关层进行均衡转发,以平衡服务实例的处理能力。
第一步、项目添加nacos依赖

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

第二步、将入门配置的uri: http://localhost:8082 改为通过lb协议和服务名**,lb指的是从nacos中按照名称获取微服务,并遵循负载均衡策略**

server:
  port: 9000
spring:
  application:
    name: msa-gateway
  cloud:
    gateway:
      routes: #配置网关路由规则
        - id: route01  #路由id,自己指定一个唯一值即可
          #uri: http://localhost:8082 # 网关帮我们转发的url,即访问provider 只能一个实例,不能负载均衡
          uri: lb://msa-provider
          predicates: #匹配请求规则 断言(谓词)
            - Path=/nacos/provider/echo/**  #请求路径定义,此路径对应uri中的资源
          filters: #网关过滤器,对谓词中的内容进行判断分析及处理
            - StripPrefix=1 #转发之前去掉path中的第一层路径,例如nacos

启动服务,进行访问测试,并反复刷新分析

四、Predicate(断言)增强分析

说明:Predicate(断言)又称谓词,用于条件判断,只有断言结果都为真,才会真正的执行路由。断言其本质就是定义路由转发的条件。

SpringCloud Gateway包括一些内置的断言工厂,所有这些断言都与http请求的不同属性相匹配

基于Datetime类型的断言工厂

此类型的断言根据时间做判断,主要有三个:

1) AfterRoutePredicateFactory:判断请求日期是否晚于指定日期
2) BeforeRoutePredicateFactory:判断请求日期是否早于指定日期
3) BetweenRoutePredicateFactory:判断请求日期是否在指定时间段内

基于header的断言工厂HeaderRoutePredicateFactory

判断请求Header是否具有给定名称且值与正则表达式匹配。例如:-Header=X-Request-Id, \d+

基于Method请求方法的断言工厂

MethodRoutePredicateFactory接收一个参数,判断请求类型是否跟指定的类型匹配。例如:-Method=GET

基于Query请求参数的断言工厂,QueryRoutePredicateFactory 

接收两个参数,请求param和正则表达式, 判断请求参数是否具 有给定名称且值与正则表达式匹配。例如:-Query=pageSize,\d+

spring:
  application:
    name: sca-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true #开启通过服务名查找服务实例的特性
      routes: #配置网关路由规则
        - id: route01 #路由id,自己指定一个唯一值即可
          #uri: http://localhost:8082 # 网关帮我们转发的url,即访问provider 只能一个实例,不能负载均衡
          uri: lb://sca-provider
          predicates: #匹配请求规则 断言(谓词)
            - Path=/nacos/provider/echo/**  #请求路径定义,此路径对应uri中的资源
            #- After=2021-08-01T23:59:59.789+08:00[Asia/Shanghai] #在2020-08-01时间后才可以访问
            #- Before=2021-08-25T23:59:59.789+08:00[Asia/Shanghai] #在2020-08-01时间后之前才可以访问
            #- Between=2020-08-03T23:59:59.789+08:00[Asia/Shanghai],2023-08-05T23:59:59.789+08:00[Asia/Shanghai]
            #- Header=X-Request-Id, \d+  #请求头 \d+ 正则表达式,这里表示任意数字
            - Method=GET #请求方式
            #- Query=pageSize,\d+ #请求参数
          filters: #网关过滤器,对谓词中的内容进行判断分析及处理
            - StripPrefix=1 #转发之前去掉path中的第一层路径,例如nacos
            #- AddRequestHeader=X-Request-Foo,Bar #往转发地址的请求头加入数据 X-Request-Foo请求头的名称,Bar请求头的值

说明:当条件不满足时,则无法进行路由转发,会出现404异常。

五、过滤器增强

过滤器(Filter)就是在请求传递过程中,对请求和响应做一个处理。Gateway 的Filter从作用范围可分为以下两种:
GatewayFilter:应用到单个路由或者一个分组的路由上。
GlobalFilter:应用到所有的路由上。

1 局部过滤器

基于AddRequestHeaderGatewayFilterFactory,为原始请求添加Header

例如,为原始请求添加名为 X-Request-Foo ,值为 Bar 的请求头:

spring:
  cloud:
    gateway:
      routes:
        - id: add_request_header_route
          uri: https://example.org
          filters:
            - AddRequestHeader=X-Request-Foo, Bar
基于AddRequestParameterGatewayFilterFactory,为原始请求添加请求参数及值,

例如,为原始请求添加名为foo,值为bar的参数,即:foo=bar

spring:
  cloud:
    gateway:
      routes:
        - id: add_request_parameter_route
          uri: https://example.org
          filters:
            - AddRequestParameter=foo, bar

2 全局过滤器

在系统初始化时加载,并作用在每个路由上。通过全局过滤器可以实现对权限的统一校验,安全性验证等功能。一般内置的全局过滤器已经可以完成大部分的功能,但是对于企业开发的一些业务功能处理,还是需要我们 自己编写过滤器来实现的

/**
 * 定义一个全局过滤器,模拟统一认证,Spring Cloud Gateway规范中,要求所有全局过滤器必须实现GlobalFilter接口
 */
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    /**
     * 对请求进行过滤
     *
     * @param exchange (网管层面的交换器,通过此对象获取请求和响应对象)
     * @param chain    过滤器链(这个过滤器链中包含0个或多个过滤器)
     * @return Mono是Spring WebFlux技术中的0个或1个响应序列
     * http://localhost:9000/nacos/provider/echo/9000?username=admin
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //获取请求和响应对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //获取请求参数数据,并进行数据响应
        String username = request.getQueryParams().getFirst("username");
        if (!"admin".equals(username)) {
            System.out.println("认证失败");
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            //终止请求继续传递
            return response.setComplete();
        }
        //请求链继续传递(假如用户名为admin则继续执行后续操作)
        return chain.filter(exchange);
    }

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

六、限流实现

网关是所有请求的公共入口,所以可以在网关进行限流,而且限流的方式也很多,这里采用Sentinel组件来实现网关的限流。Sentinel支持对SpringCloud Gateway、Zuul等主流网关进行限流

1 限流快速入门

添加sentinel限流的相关依赖

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
        </dependency>

yml文件添加sentinel相关配置

spring:
  application:
    name: msa-gateway
  cloud:
    sentinel:
      transport:
        port: 8719 #客户端监控API的端口
        dashboard: localhost:8180 #Sentinel 控制台地址
      eager: true #取消Sentinel控制台懒加载,即项目启动即连接

最后所有yml文件的内容如下

server:
  port: 9000
spring:
  application:
    name: msa-gateway
  cloud:
    gateway:
      routes: #配置网关路由规则
        - id: route01  #路由id,自己指定一个唯一值即可
          #uri: http://localhost:8082 # 网关帮我们转发的url,即访问provider 只能一个实例,不能负载均衡
          uri: lb://msa-provider
          predicates: #匹配请求规则 断言(谓词)
            - Path=/nacos/provider/echo/**  #请求路径定义,此路径对应uri中的资源
          filters: #网关过滤器,对谓词中的内容进行判断分析及处理
            - StripPrefix=1 #转发之前去掉path中的第一层路径,例如nacos
    sentinel:
      transport:
        port: 8719 #客户端监控API的端口
        dashboard: localhost:8180 #Sentinel 控制台地址
      eager: true #取消Sentinel控制台懒加载,即项目启动即连接

# 开发阶段打开gateway日志
logging:
  level:
    org.springframework.cloud.gateway: debug

启动网关项目,添加sentinel的jvm参数,通过此菜单可以让网关服务在sentinel控制台显示不一样的菜单

-Dcsp.sentinel.app.type=1

在这里插入图片描述
在sentinel面板中设置限流策略
在这里插入图片描述
测试限流策略是否生效
在这里插入图片描述

2 基于请求属性限流

在这里插入图片描述
Postman测试效果如下
在这里插入图片描述

3 自定义API维度限流

自定义API分组,是一种更细粒度的限流规则定义,它允许我们利用sentinel提供的API,将请求路径进行分组,然后在组上设置限流规则

第一步:新建API分组
在这里插入图片描述

第二步:新建分组流控规则
在这里插入图片描述
访问测试
在这里插入图片描述

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐