Spring Cloud Gateway: 网关

网关

API网关就是实现了前端项目和服务端项目之间的统一入口
Nginx实现的是用户和前端项目之间调用的入口
Ribbon实现是后端服务之间相互调用的负载均衡算法
在这里插入图片描述

API网关作用就是把各个服务对外提供的API汇聚起来,让外界看起来是一个统一的接口。同时在网关中提供额外的功能。

Hello world

一.搭建Eureka Server
二.搭建application client集群
三.搭建Gateway网关微服务
1.导入依赖

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

2.编写yml配置文件

server:
  port: 9999
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
spring:
  application:
    name: cloud-gateway
  cloud: # spring cloud相关配置的常用前缀
    gateway: # 网关技术配置前缀
      discovery: # 自动发现工具
        locator: # 本地逻辑
          enabled: true # 开启自动发现工具的本地路由逻辑
          lower-case-service-id: true # 把从EurekaServer上发现的服务名称,转换成全小写,只要小写的服务名称才能访问,大写的不行!!!!!!

四.启动服务
自动发现工具的本地路由规则是:
请求路径 - http://网关IP:网关端口/微服务的服务名/要访问的具体地址
gateway自动解析,把请求地址中的’微服务的服务名’截取,从Eureka Client发现的服务列表中查看,如果有同名服务,则开始转发。
如: http://localhost(网关IP):9999(网关端口)/application(服务集群名)/save(具体访问地址)

路由: Route

一个路由包含ID、URI、Predicate集合、Filter集合。
在Route中ID是自定义,但唯一,URI就是一个地址。
谓词: 路由前的条件和内容.
Filter负责在路由后,代理服务“之前”或“之后”做的一些事情。

谓词: Predicate

对前端发来的请求进行校验
1.Path: 用于匹配路由地址规则的谓词。

spring:
  cloud: 
    gateway:
      discovery:
        locator:
          enabled: false # 关闭自动发现工具的本地路由逻辑
          lower-case-service-id: true 
      routes: 
        - id: application-service # 路由的唯一名称,随便定义,不重复即可
          uri: lb://application-service # 规则满足后,转发到的地址。lb是spring cloud gateway支持的一种协议名
          predicates: Path=/edit # 谓词  路由地址规则  

Path=/edit/** 代表所有访问url中代用edit的都可以走这个路由

2.Query: 校验请求url是否包含指定的请求参数及参数值是否符合要求,只能校验请求地址参数,也就是 /path?参数

方式一: 只能指定是否有指定请求参数,不能指定参数值
predicates: Path=/demo/**,Query=abc

方式二: 常用,可以指定请求参数及参数值,但是不能指定参数值中带有","的参数值
predicates: 
  - Path=/demo/**
  - Query=name,fs.* # 请求参数必须包含name,请求参数的值必须以 fs开头
  - Query=age,18 # 请求参数必须包含age

方式三:
predicates: 可以指定请求参数值中带有","的参数值
  - Path=/demo02
  - name: Query
    args:
      param: abc
      regexp: 12,3

3.Header: 校验请求中是否包含指定的请求头及请求头数值是否符合要求
4.Method: 请求方式。支持多个值,使用逗号分隔
5.Cookie: 包含指定Cookie名和满足特定正则要求的值: Cookie参数值要是正则表达式
**

  predicates:
    - Path=/service/**  
    - Header=Host,.* # 请求头必须有Host,值为任意字符串
    - Header=abc,123 # 请求头中包含abc,且值为123
	- Method=GET,POST # 请求方式必须是GET或POST
    - Cookie=name,bjsxt.* # 请求必须包含名称是name,值符合bjsxt开头的cookie。

6.RemoteAddr: 允许访问的客户端IP

  predicates:
    - Path=/service/** 
    - RemoteAddr=192.168.41.252 # 客户端IP必须是192.168.41.252

7.Host: 匹配请求中Host请求头的值。满足Ant模式(之前在Spring Security中学习过)可以使用:

  • ? 匹配一个字符
  • * 匹配0个或多个字符
  • ** 匹配0个或多个目录
  predicates:
    - Path=/service/** 
    - Host=127.0.0.1:9999 # 请求头Host值必须是127.0.0.1:9999

8.时间限制:
下面三个一般只存在一个即可
Before: 在指定时间点之前
After: 在指定时间点之后。
Between: 请求时必须在设定的时间范围内,才进行路由转发。

  predicates:
    - Path=/service/** 
    - Before=2022-10-01T18:00:00.000+08:00[Asia/Shanghai] # 2022-10-01晚18点前可以访问
    - After=2020-10-01T08:00:00.000+08:00[Asia/Shanghai] # 2020-10-01早8点后可以访问
	- Between=2020-10-01T08:00:00.000+08:00[Asia/Shanghai],2022-10-01T18:00:00.000+08:00[Asia/Shanghai] # 2020-10-01早8点后,2022-10-01晚18点前可以访问

9.Weight: 对服务名指定分组合权重
Weight=组名,负载均衡权重
例: 在Eureka中注册两个服务,这个服务(项目)是相同的,应用程序名分别叫做application-service1和application-service2。
Gateway在路由匹配时application-service1将占20%,application-service2将占80%。

- id: application-service1
  uri: lb://application-service1
  predicates:
    - Path=/service/**
    - Weight=group1,2
- id: application-service2
  uri: lb://application-service2
  predicates:
    - Path=/service/**
    - Weight=group1,8

过滤器: Filter

路由转发之后,被代理的服务执行前后运行的
路由过滤器:框架内置的Filter实现都是路由过滤器,都是GatewayFilter实现类型。
全局过滤器:框架未内置全局过滤器实现,需自定义。全局过滤器需实现接口GlobalFilter。

          filters: #/配置路由规则
            - stripPrefix=1 #跳过路径中的前几级发送给下游地址
            - AddRequestHeader=sxt,123 #给下游请求添加请求头
            - AddRequestParameter=abc,123 #给下游服务传递请求参数
            - AddResponseHeader=cou,javaEE #设置响应头
            - DedupeResponseHeader=cou,RETAIN_FIRST #当相应头重复后﹑保留第一个
            - SetPath=/{
    
    segment} #重新的设置路徭

Gateway实现限流: RequestRateLimiter过滤器

常见限流算法
一.计数器算法: 每个请求让计数器加一,当到达设定值后,其他的请求都拒绝。到下一秒开始时,计数清零,重新开始计数。
二.漏桶算法: 不论请求多少,都以恒定速度处理请求
三.令牌桶算法: 在桶中放令牌,请求获取令牌后才能继续执行,不论请求多少,执行速率都由生产令牌的速率控制.
令牌桶算法
1.导入依赖

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

2.新建密钥解析器
注意这里使用IP解析

@Component
public class MyKeyResolver implements KeyResolver {
    
    
    @Override
    public Mono<String> resolve(ServerWebExchange exchange) {
    
    
        String ip = exchange.getRequest() // 获取请求对象
                .getRemoteAddress() // 获取客户端地址对象 InetSocketAddress
                .getAddress() // 获取客户端地址对象 InetAddress
                .getHostAddress(); // 获取客户端的主机地址(IP或唯一的主机名)
        return Mono.just(ip); // 创建返回结果对象
    }
}

3.yml配置文件

          filters:
            - name: RequestRateLimiter
              args:
                keyResolver: '#{@xxx}'
                redis-rate-limiter.replenishRate: 1 # 每秒令牌生成速率
                redis-rate-limiter.burstCapacity: 2 # 令牌桶容量上限

4.测试:
使用JMeter访问 http://localhost:9999/save 若干次,结果是,第一秒可处理2个请求(令牌桶上限),后续每秒可以处理1个请求(令牌生成速率)。

使用Gateway实现服务降级

1.导入依赖

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

2.在Gateway的controller创建托底方法

@RestController
public class MyController {
    
    
    @RequestMapping("/fallback")
    public String show(){
    
    
        return "托底方法";
    }
}

3.yml配置

          filters:
            - name: Hystrix
              args:
                name: fallback # 随意定义的名称。相当于@HystrixCommand注解中的commandKey属性。
                # 如果转发的服务不可用,请求转发到当前Gateway模块映射路径为fallback(随意命名和映射路径一致即可)的控制单元上。
                fallbackUri: forward:/fallback 

自定义全局过滤器

/**
 * 自定义全局过滤器。
 * 必须实现接口GlobalFilter
 * 当前类型的对象,必须被spring容器管理。
 * 无须配置,所有路由都生效。
 *
 * 执行顺序:
 *  先执行网关过滤器,后执行全局过滤器
 *  多个全局过滤器,执行顺序由Spring boot扫描管理当前对象的顺序决定。
 *  每个过滤器,都是完整执行后,才执行下一个过滤器。
 */
@Component
public class MyGlobalFilter implements GlobalFilter {
    
    
    /**
     * 过滤方法。
     * 实现上,只有唯一的要求。必须调用方法chain.filter(exchange),并把方法的返回值,返回。
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
    
        System.out.println("前置全局过滤");
        //放行/执行下一个过滤器
        Mono<Void> result = chain.filter(exchange);
        System.out.println("后置全局过滤");
        return result;
    }
}

GateWay中执行流程

1.网关客户端访问Gateway网关,Gateway中Handler Mapping对请求URL进行处理。
2.处理完成后,交由Web Handler处理,Web Handler 运行时会被Filter过滤。Filter中前半部分代码是处理请求的代码。
3/处理完成后调用真实被代理的服务;被代理服务返回响应结果,结果会被Filter中后半部分代码过滤处理;
4,操作完成后把结果返回给Web Hanlder,再返回给Handler Mapping,最终响应给客户端。

GateWay的底层: 底层框架是Netty(NIO) :对java.net中内容进行封装 【NIO】 AIO进行封装

猜你喜欢

转载自blog.csdn.net/m0_56182317/article/details/130217124