Spring Cloud Gateway 入门与实战

一、网关

在微服务框架中,网关是一个提供统一访问地址的组件,它充当了客户端和内部微服务之间的中介。网关主要负责流量路由和转发,将外部请求引导到相应的微服务实例上,同时提供一些功能,如身份认证、授权、限流、监控、日志记录等。

二、网关作用

  1. **路由功能:**网关可以根据目标地址的不同,选择最佳的路径将数据包从源网络路由到目标网络。它通过维护路由表来确定数据包的转发方向,并选择最优的路径。
  2. **安全控制:**网关可以实施网络安全策略,对进出的数据包进行检查和过滤。它可以验证和授权来自源网络的数据包,并阻止未经授权的访问。防火墙是一种常见的网关设备,用于过滤和保护网络免受恶意攻击和未经授权的访问。
  3. **协议转换:**不同网络使用不同的通信协议,网关可以进行协议转换,使得不同网络的设备可以互相通信。例如:将HTTPS 协议转换成 HTTP 协议。
  4. **网络地址转换(NAT):**网关可以执行网络地址转换,将内部网络使用的私有 IP 地址转换为外部网络使用的公共 IP 地址,以实现多台计算机共享一个公共 IP 地址上网

三、Spring Cloud Gateway 组成

  1. **路由:**定义了请求应该被转发到哪个目标地址。路由由 ID、目标 URI 、断言、和过滤器组成。通过配置多个路由,可以实现不同请求的路由规则。
  2. **断言:**用于匹配请求条件,如果请求匹配断言条件,则会被映射到对应目标地址上。断言可以基于请求的路径、请求头、请求参数等信息进行匹配。
  3. **过滤器:**用于在请求路由前或路由后进行一些处理,如添加头部信息、修改请求体等。过滤器可以在全局范围或特定路由范围内配置,多个路由器可以组成过滤器链。

四、Spring Cloud Gateway 的使用

使用步骤如下:

1. 添加 Gateway 依赖

XML 复制代码
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

2. 设置网关路由规则

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service
        uri: http://192.168.146.1:8082 #映射的ip和端口
        predicates:
        - Path=/user/**,/log/** #当请求路径满足配置的path时,将ip和端口映射到上面的uri

五、断言(Predicate)类型

Spring Cloud Gateway 支持的断言类型目前有 12 中, 包含以下这些:

  1. 根据时间匹配:
  • After: 请求在指定时间之后才匹配
  • Before:请求在指定时间之前才匹配
  • Between:请求在指定时间中间才匹配
  1. Cookie:匹配求中的Cookie值

  2. Header:匹配请求中的 Header 值

  3. Host:匹配请求中的 Host 值

  4. Method:匹配请求头中的 Method 的值

  5. Path:匹配请求路径

  6. Query:匹配请求参数

  7. RemoteAddr:匹配请求的 IP 地址,支持 IPV4 和 IPV6

  8. Weight:根据权重来分发请求,权重根据 group 来计算

  9. XForwardedRemoteAddr:根据 X-Forwarded-For 匹配

5.1 根据时间匹配

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service
        uri: http://192.168.146.1:8082
        predicates:
        - Path=/user/**,/log/**
        - Before=2024-07-15T19:00:00.000+08:00[Asia/Shanghai] #上海时间2024-7-15 19点前允许访问

between

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service
        uri: http://192.168.146.1:8082
        predicates:
        - Path=/user/**,/log/**
        - Between=2024-07-13T19:00:00.000+08:00[Asia/Shanghai],2024-07-15T19:00:00.000+08:00[Asia/Shanghai] #上海时间2024-7-13 19点 ~ 2024-7-15 19点之间允许访问

5.2 根据 Header 匹配

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service
        uri: http://192.168.146.1:8082
        predicates:
        - Path=/user/**,/log/**
        - Between=2024-07-13T19:00:00.000+08:00[Asia/Shanghai],2024-07-15T19:00:00.000+08:00[Asia/Shanghai] #上海时间2024-7-15 19点前允许访问
        - Header= Ip2contry,\w+ 

其中 "Ip2contry" 表示 Header 中的 key ,而 "\w+" 表示的是key 的值,值可用正则表达式进行匹配

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service
        uri: http://192.168.146.1:8082
        predicates:
        - Path=/user/**,/log/**
        - Between=2024-07-13T19:00:00.000+08:00[Asia/Shanghai],2024-07-15T19:00:00.000+08:00[Asia/Shanghai] #上海时间2024-7-15 19点前允许访问
        - Header= Ip2contry,\w+
        - Cookie= author,zhangsan

5.4 根据 weight 进行配置

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service
        uri: http://169.254.165.28:8081
        predicates:
        - Weight=group2,10
      - id: user-service2
        uri: http://169.254.165.28:8082
        predicates:
        - Weight=group2,90

group2 表示分组,10 表示所在分组所占权重

六、Spring Cloud Gateway + Nacos + LoadBalancer 实现企业级网关

6.1 添加依赖

XML 复制代码
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

6.2 设置路由规则

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service
        uri: lb://user-service #user-service #调用服务注册在 nacos 中的名称
        predicates:
        - Path=/user/**
    nacos:
      discovery:
        server-addr: localhost:8848
        password: nacos
        username: nacos
        register-enabled: false

七、过滤器

过滤器作用:

  • **功能扩展和定制:**过滤器可以用于对现有功能进行扩展和定制。通过拦截和处理数据流或事件流,可以修改数据,增加额外的功能逻辑,实现特定的业务需求。例如,可以使用过滤器在请求之前进行身份验证、权限控制,或者在响应之后进行日志记录、数据转换等操作。
  • **数据校验和过滤:**过滤器可以用于对数据进行校验和过滤。在接收到数据之后,可以使用过滤器对数据进行检查,验证数据的合法性,过滤掉无效或不符合要求的数据。这有助于保证数据的准确性、完整性和安全性。
  • **安全保护:**过滤器可以用于提供安全保护措施,可以使用过滤器对输入的请求进行检查和清洗,以防止潜在的安全漏洞,例如跨站脚本攻击(XSS)、跨站请求伪造(CSRF) 等攻击。过滤器还可以进行访问控制,验证权限和实施安全策略。
  • 性能优化:过滤器可以用于性能优化。例如,在数据处理流水线中,可以使用过滤器对数据进行转换、过滤或缓存,以提高处理速度和效率。过滤器还可以用于数据压缩、缓存预热等场景,减少数据传输和处理的成本。
  • 统一处理和逻辑服用:过滤器提供了一种统一的处理方式,可以在不同的组件或模块上应用相同的逻辑或处理方式。通过将处理逻辑抽象为过滤器,可以避免重复代码、统一错误处理和统一异常处理等,提高代码复用性和可维护性。

7.1 内置局部过滤器

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service-demo
        uri: lb://user-service
        predicates:
        - Path=/user/**
        filters:
        - AddResponseHeader=soruce,userservice

其中 "AddResponseHeader" 表示添加返回头过滤器,前面的值 " source" 为 key ,后面的值 "value" 为 value

7.2 AddRequestHeader

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service-demo
        uri: lb://user-service
        predicates:
        - Path=/user/**
        filters:
        - AddResponseHeader=soruce,userservice
        - AddRequestHeader= my-request-market, kaikai

在下游服务调用接口中打印所有的 Header 查看添加的 Header 信息,代码如下:

java 复制代码
@RequestMapping("/getHeader")
public void getHeader(HttpServletRequest request){
    Enumeration<String> headers= request.getHeaderNames();
    while (headers.hasMoreElements()){
        String key=headers.nextElement();
        String value= request.getHeader(key);
        System.out.println(key+ " : "+value);
    }
}

7.3 AddRequestParameter

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service-demo
        uri: lb://user-service
        predicates:
        - Path=/user/**
        filters:
        - AddRequestParameter= id,209

后续请求中带有key为id,value 209 的参数

java 复制代码
    @RequestMapping("/getID")
    public Integer getID(@RequestParam("id")Integer id){
        return id;
    }

    @RequestMapping("/getId")
    public String getId(HttpServletRequest request){
        return request.getParameter("id");
    }

7.4 PrefixPath

在请求的 url 前面添加前缀,例如请求的是 /user, 添加了 PrefixPath为 /new,那么后续访问的地址就为 "/new/user"

7.5 限流过滤器- RequestRateLimiter

网关限流过滤器,Spring Cloud Gateway 内置了限流功能,它使用的限流算法是令牌桶的限流算法

**令牌桶限流算法:**令牌安固定的速率被放入令牌桶中,桶中最多存放 N个令牌(Token),当桶装满时,新添加的令牌被丢弃或拒绝。当请求到达时,将从桶中删除 1 个令牌。令牌中的令牌不仅可以被移除,还可以往里添加,所以为了保证接口随时有数据通过,必须不停地往桶里加令牌。由此可见,往桶里加令牌的速度就决定了数据通过接口的速度。我们通过控制往令牌桶里加令牌的速度从而控制接口的流量。

Spring Cloud Gateway 当前版本支持 和 Redis 一起实现限流功能,它的实现步骤总共分为以下三步:

1. 添加 Reids 框架依赖

XML 复制代码
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

2. 创建限流规则

创建一个类,根据 IP 进行限流:

java 复制代码
@Component
public class IpKeyResolver implements KeyResolver {
    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
        System.out.println(exchange.getRequest().getRemoteAddress().getHostString());
        System.out.println(exchange.getRequest().getRemoteAddress().getHostName());
        return Mono.just(exchange.getRequest().getRemoteAddress().getHostString());
    }
}

3. 配置限流规则

在项目的配置文件中,配置以下内容:

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service-demo
        uri: lb://user-service
        predicates:
        - Path=/user/**
        filters:
          - name: RequestRateLimiter
            args:
               redis-rate-limiter.replenishRate: 1
               redis-rate-limiter.burstCapacity: 1
               keyResolver: '#{@ipKeyResolver}'
    nacos:
      discovery:
        username: nacos
        password: nacos
        server-addr: localhost:8848
  data:
    redis:
      host: 114.115.149.19
      port: 6378
      database: 0

其中,name 必须等于 "RequestRateLimiter" 内置限流过滤器,其他参数:

  • redis-rate-limiter.replenishRate:令牌填充速度:每秒允许请求数
  • redis-rate-limiter.burstCapacity: 令牌桶容量:最大令牌数
  • redis-rate-limiter.requestedTokens: 每次请求消耗的令牌数
  • keyResolver: 根据哪个 key 进行限流,它的值时 spEL 表达式。

7.6 Retry

配置:

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service-demo
        uri: lb://user-service
        predicates:
        - Path=/user/**
        filters:
        - name: Retry
          args:
            retries: 3 #重试次数
            statuses: Gateway Timeout #状态码,详情参考 HttpResponseStatus.class
            method: GET
#            series: CLIENT_ERROR
            backoff:
              firstBackoff: 1000ms #第一次重试间隔
              maxBackoff: 10000ms   #最大重试间隔时间
              factor: 2 #firstBackoff * (factor ^ n) 重试系数,如果重试间隔时间超过最大重试间隔时间,按照最大重试间隔时间来算
              basedOnPreviousValue: false #根据上次重试时间加上重试系数来计算

代码调试:

java 复制代码
    @RequestMapping("/getstatus")
    public void getStatus(HttpServletResponse response){
        System.out.println("==============Do GetStatus Method ===================");
        response.setStatus(403);
    }
  • name :一定要等于 "Retry" ,因为 "Retry" 就是内置的过滤器的名字
  • retries: 重试次数
  • statuses:状态码 ,匹配对应状态码响应,并重试
  • series: 状态码配置,符合某段状态码才会进行重试逻辑,默认值是SERVER_ERROR,值是 5 ,也就是 5XX 开头的状态码。
    1XX:INFORMATIONAL
    2XX:SUCCESSFUL
    3XX:REDIRECTION
    4XX:CLIENT_ERROR
    5XX:SERVER_ERROR
  • backoff:重试指数配置策略,默认关闭

注:statuses 和 retries 是且的关系。

7.7 内置全局过滤器

bash 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: user-service-demo
        uri: lb://user-service
        predicates:
        - Path=/user/**
        filters:
#        - AddResponseHeader=soruce,userservice
      default-filters:
        - AddResponseHeader=soruce,userservice

7.8 自定义过滤器

java 复制代码
package com.gatewayservicesoa.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.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
public class AuthFilter implements GlobalFilter, Ordered {
    /**
     * @param exchange 要执行的事件
     * @param chain    过滤器链
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //此处使用的是相应试 HTTP
        ServerHttpRequest request=  exchange.getRequest();
        ServerHttpResponse response=  exchange.getResponse();
        if(request.getQueryParams().getFirst("name")!=null && request.getQueryParams().getFirst("name").equals("name")
                && request.getQueryParams().getFirst("password")!=null && request.getQueryParams().getFirst("password").equals("123")){
            return chain.filter(exchange);
        }else {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
    }

    @Override
    public int getOrder() {
        //过滤器的执行顺序,值越小,越早执行
        return 0;
    }
}

八、工作原理

客户但向 Spring Cloud Gateway 发出请求,网关映射处理程序(Gateway Handler Mapping) 会根据请求路径进行路由匹配,然后再将其发送到网关 Web 处理器(Gateway Web Handler) 进行处理。此时处理器会经过过滤链(filter) 进行处理,而过滤器又分为 前置过滤器和后置过滤器,之后才会将请求发送给目标服务(也称代理的服务)。

相关推荐
qq_4419960529 分钟前
Mybatis官方生成器使用示例
java·mybatis
巨大八爪鱼36 分钟前
XP系统下用mod_jk 1.2.40整合apache2.2.16和tomcat 6.0.29,让apache可以同时访问php和jsp页面
java·tomcat·apache·mod_jk
PGCCC36 分钟前
【PGCCC】Postgresql 存储设计
数据库·postgresql
码上一元2 小时前
SpringBoot自动装配原理解析
java·spring boot·后端
计算机-秋大田3 小时前
基于微信小程序的养老院管理系统的设计与实现,LW+源码+讲解
java·spring boot·微信小程序·小程序·vue
PcVue China3 小时前
PcVue + SQL Grid : 释放数据的无限潜力
大数据·服务器·数据库·sql·科技·安全·oracle
魔道不误砍柴功4 小时前
简单叙述 Spring Boot 启动过程
java·数据库·spring boot
失落的香蕉5 小时前
C语言串讲-2之指针和结构体
java·c语言·开发语言
锐策5 小时前
〔 MySQL 〕数据库基础
数据库·mysql
枫叶_v5 小时前
【SpringBoot】22 Txt、Csv文件的读取和写入
java·spring boot·后端