0
点赞
收藏
分享

微信扫一扫

SpringCloud 【Gateway-API网关】


GateWay -API网关

​ SpringCloud Alibaba 风格组件​

文章目录

  • ​​GateWay -API网关​​
  • ​​前言​​
  • ​​什么是API网关​​
  • ​​网关的组成​​
  • ​​路由转发​​
  • ​​过滤器​​
  • ​​一、SpringCloud Alibaba Gateway介绍​​
  • ​​1.1 简介​​
  • ​​1.2 名词解释​​
  • ​​1.2.1 Route​​
  • ​​1.2.2 Predicate​​
  • ​​1.3 工作原理图​​
  • ​​二、小案例演示​​
  • ​​2.1 构建一个商品销售的微服务框架​​
  • ​​2.2 编写一个SpringCloud Alibaba的Gateway的yml配置文件​​
  • ​​2.3 测试​​
  • ​​三、常用的断言策略​​
  • ​​3.1时间戳断言​​
  • ​​3.2 Cookie断言​​
  • ​​3.3 header路由断言​​
  • ​​3.4 Host路由匹配规则​​
  • ​​3.5 Method路由匹配规则​​
  • ​​3.6 Path匹配路由规则​​
  • ​​3.7 Weight权重匹配规则​​
  • ​​四、Gateway过滤器​​
  • ​​4.1 Gateway路由Filter工厂介绍​​
  • ​​4.2 常用GatewayFilter实例说明​​
  • ​​4.2.1 前置过滤器​​
  • ​​:one: AddRequestHeader GatewayFilter Factory​​
  • ​​:two:The RewritePath GatewayFilter Factory​​
  • ​​4.2.2 后置过滤器​​
  • ​​:one:The SetStatus GatewayFilter Factory​​
  • ​​:two:AddResponseHeader GatewayFilter Factory​​
  • ​​4.3 Gateway全局Filter GlobalFilter​​
  • ​​4.4 自定义过滤器:fire::fire:​​
  • ​​4.4.1 自定义Gateway过滤器​​
  • ​​4.4.2 自定义GlobalFilter过滤器​​
  • ​​五、Gateway网管限流​​
  • ​​5.1 令牌桶网管限流算法​​
  • ​​5.2 Gateway网关限流实例​​
  • ​​5.2.1 URI限流​​
  • ​​5.2.2 参数限流​​
  • ​​5.2.3 ip限流​​

前言

什么是API网关

API网关作用就是把各个服务对外提供的API汇聚起来,让外界看起来就像是一个统一的接口。同时也可以在网关中提供额外的功能。
🔥总结:​网关就是所有项目的统一的入口​

网关的组成

网关 = 路由转发+过滤器(额外编写的功能)

路由转发

接受外界的请求,通过网关的路由转发,转发到后端的服务上
如果只有一个服务功能看起来就像是之前所学习的nginx反向代理服务器一样,外界访问nginx,由nginx来做负载均衡,后请求转发到对应的服务器上。

过滤器

网关非常重要的功能就是过滤器。
过滤器中提供了默认的25内置功能还能自定义功能。
对于我们来说比较常用的功能有:​​​网关的容错,限流以及请及相应的额外处理。​

​提示:以下是本篇文章正文内容,下面案例可供参考​

一、SpringCloud Alibaba Gateway介绍

1.1 简介

SpringCloud Alibaba Gateway是Spring Cloud的二级子项目,提供了微服务网关功能,包含:权限安全、监控/指标等功能。

1.2 名词解释

在学习Gateway时里面有一些名词需要提前解释了解,他对于后面的学习是与很大的帮助的。

1.2.1 Route

Route中文称为路由,Gateway 里面的Route是主要学习内容,一个Gateway项目可以包含多个Route。

一个路由包含ID​URI​、[Predicate集合]、[Filter集合]。

在Router中ID是自定义的,URI就是一个地址,剩下的Predicate和Filter学习明白了,Route就清楚了。

SpringCloud 【Gateway-API网关】_自定义

1.2.2 Predicate

Predicate:谓词

谓词对学习Gateway比较重要的一点!!

简单点理解谓词就是一些附加条件和内容。

2.3 Filter
所有生效的Filter都是GatewayFilter的实例。

在Gateway运行过程中Filter 负责在代理服务"之前”或“之后”去做一些事情。

1.3 工作原理图

SpringCloud 【Gateway-API网关】_gateway_02

  1. 客户端向SpringCloud Gateway发出请求,​​然后在Gateway Handler Mapping中找到相应的请求映射地址的路由匹配,将其发送到Gateway web handler​
  2. ​Handler再通过指定的过滤器链来请求发送到我们实际的业务逻辑,然后再返回。​​过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。
  3. Filter会根据其发出的请求类型来做出相应的响应。

二、小案例演示

2.1 构建一个商品销售的微服务框架

注意要使用Gateway需要引入其依赖文件

<dependencies>
<!--引入gateway的依赖文件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>

不能引入web依赖,只需要在父工程中声明版本即可,否则会报错

2.2 编写一个SpringCloud Alibaba的Gateway的yml配置文件

server:
port: 81 # 统一访问的端口为81端口
servlet:
context-path: /

spring:
application:
name: gateway-server
# 路由配置
cloud:
gateway:
routes: # 定义路由规则 可以定义多个路由 统一的路径管理
- id: product # 路由ID 保证其唯一 一般与项目名保持一致即可
uri: http://localhost:8080/ # 路由地址 项目的地址
predicates: # 断言规则
- Path=/product/**

- id: order # 路由ID 唯一保证 与项目名保持一致即可
uri: http://localhost:8081/ # 路由地址
predicates: # 断言规则
- Path=/order/**

2.3 测试

SpringCloud 【Gateway-API网关】_spring cloud_03


SpringCloud 【Gateway-API网关】_自定义_04


SpringCloud 【Gateway-API网关】_spring_05

所以,我们可以不恰当的把gateway理解成我们学校宿舍的舍管阿姨 或者保安队长,具有统一协调和分配的权力

三、常用的断言策略

SpringCloud Gateway的官网为我们提供了11中断言策略
官网地址 :​​​https://cloud.spring.io/spring-cloud-gateway/reference/html/​​

  • The After Route Predicate Factory
  • The Before Route Predicate Factory
  • The Between Route Predicate Factory
  • The Cookie Route Predicate Factory
  • The Header Route Predicate Factory
  • The Host Route Predicate Factory
  • The Method Route Predicate Factory
  • The Path Route Predicate Factory
  • The Query Route Predicate Factory
  • The RemoteAddr Route Predicate Factory

3.1时间戳断言

​The After Route Predicate Factory​​ 可以通过 下述的方法来获得符合格式的时间戳字符串

server:
port: 81 # 统一访问的端口为81端口
servlet:
context-path: /

spring:
application:
name: gateway-server
# 路由配置
cloud:
gateway:
routes: # 定义路由规则 可以定义多个路由 统一的路径管理
- id: product # 路由ID 保证其唯一 一般与项目名保持一致即可
uri: http://localhost:8080/ # 路由地址 项目的地址
predicates: # 断言规则
- Path=/product/**
- After=2022-06-18T19:16:43.338+08:00[Asia/Shanghai] # 在这个时间戳之后的请求才可以

解释说明:​ 使用了After的断言策略,就相当于给Path的策略上又加了一个条件。请求只有当先符合了路径与/product/xx的条件后,在符合请求的时间在2022-06-18T19:16:43.338+08:00之后的请求才可以被真正的响应到。

After是在xx时间节点之后的请求,才可以被通过

​故同理可以得出Before是之前的请求,Between是在两个时间节点之间的请求​

SpringCloud 【Gateway-API网关】_gateway_06

3.2 Cookie断言

使用Cookie断言有两个参数,​​一个是Cookie名称;一个Java正则表达式。​​这个断言匹配给定的cookie名和值正则匹配的请求。

server:
port: 81 # 统一访问的端口为81端口
servlet:
context-path: /

spring:
application:
name: gateway-server
# 路由配置
cloud:
gateway:
routes: # 定义路由规则 可以定义多个路由 统一的路径管理
- id: product # 路由ID 保证其唯一 一般与项目名保持一致即可
uri: http://localhost:8080/ # 路由地址 项目的地址
predicates: # 断言规则
- Path=/product/**
- Cookie=token, \d+

- id: order # 路由ID 唯一保证 与项目名保持一致即可
uri: http://localhost:8081/ # 路由地址
predicates: # 断言规则
- Path=/order/**
- Cookie=token,

这里的话,给Product服务添加一个键名为token,值为大于一个数字的cookie作为判断条件,使用postman测试

SpringCloud 【Gateway-API网关】_gateway_07

SpringCloud 【Gateway-API网关】_java_08

3.3 header路由断言

Header路由匹配规则有两个参数;​​一个报文头name;一个正则表达式​​。该断言与具有给定名称的头部信息匹配,该标头的值与正则表达式匹配,以下为实例:

- Header= X-Request-hid,

SpringCloud 【Gateway-API网关】_spring cloud_09

3.4 Host路由匹配规则

该host路由断言工厂需要一个参数:主机名的列表patterns,该模式下是带有​​,​​隔符的Ant样式的模式,断言与Host匹配模式的标头匹配,以下实例配置主机路由断言。

需要匹配的域名,多个用逗号分隔,支持Ant风格的模式匹配

- Host=**.somehost.org,**.antherhost.org

如果需要测试,我们可以修改localhost对应的主机地址的映射,在C:\WINDOWS\System32\drivers\etc目录下找到host文件,可以增加一个本机地址所对应的域名比如www.somehost,org。然后重启项目再次访问即可以实现。

3.5 Method路由匹配规则

使用Method匹配策略有一个参数,即为具体的某一个Methods,如果使用多个Methods的提交匹配方式的话,需要使用​​,​​进行分割。

- Method=GET,POST

使用PostMan进行测试,使用get或者post的方式提交的话,都是可以访问到的。但是,使用Put或者delete访问,则是404

SpringCloud 【Gateway-API网关】_java_10

3.6 Path匹配路由规则

接收一个匹配路径的参数来判断是否走路由。在该模式下,有两个参数,分别是patterns, matchTrailingSlash,第一个表示匹配的模式路径,第二个参数是一个布尔类型的值,默认是true,表示支持的模式匹配类型。

使用Path模式匹配,默认是支持Spring’的模式匹配规则,如REST风格的匹配

- Path=/order/{segment} # /order路径下的参数名为Segment的格式
- Path=/order/**# 。order路径下的所有子路径都匹配,可以有参数,也可以没有。

3.7 Weight权重匹配规则

该Weight路由断言工厂有两个参数,一个是Group,一个是Weight(一个int)。权重是按照组来进行计算的,以下的实例配置权重断言路由:

spring:
# 路由配置
cloud:
gateway:
routes:
- id: product
uri: http://localhost:8080/
predicates:
- Weight=group1,8

- id: order
uri: http://localhost:8081/
predicates:
- Weight=group1,2

这条路线上的流量大约有80%会流向http://localhost:8080/ ,有20%的流量会流向http://localhost:8081/这个分支。

四、Gateway过滤器

gateway过滤器分为Pre类型的过滤器和Post类型的过滤器。

  • Pre类型的过滤器:在请求转发到后端微服务之前执行,在Pre类型过滤器链中可以做鉴权,限流等操做。
  • Post类型的过滤器:在请求执行完成之后,再将结果返回给客户端之前执行。

在Spring Cloud Gateway中内置了许多的过滤器,Filter分两种实现,一种是​​GatewayFilter​​​和​​GlobalFilter​​,GlobalFilter会在全局过滤器应用到所有的路由上,而GatewayFilter智慧应应用到单个路由或者一个分组的路由上。

4.1 Gateway路由Filter工厂介绍

过滤器有20多个实现类,包括头部 过滤器 ,路径过滤器,类过滤器,Hystrix过滤器和变更过滤器,请求过滤器,URL过滤器,参数过滤器,状态码过滤器等等

4.2 常用GatewayFilter实例说明

4.2.1 前置过滤器

1️⃣ AddRequestHeader GatewayFilter Factory

用法:

spring:
application:
name: gateway-server
# 路由配置
cloud:
gateway:
routes:
- id: product
uri: http://localhost:8080/
predicates: # 断言规则
- Path=/product/**
filters:
- AddRequestParameter=info,

相当于给http://localhost:8080/product/** 地址上的服务的增加了一个参数,参数名为info,值为blue,然后我们在COntroller层打印输出一下这个参数,再次访问,即可在控制台输出blue

SpringCloud 【Gateway-API网关】_java_11

2️⃣The RewritePath GatewayFilter Factory

可重写的gateway过滤器工厂,

SpringCloud 【Gateway-API网关】_spring_12

- id: order  # 路由ID 唯一保证 与项目名保持一致即可
uri: http://localhost:8081/ # 路由地址
predicates:
- Path=/order/**,/api-gateway/**
filters:
- AddRequestParameter=info, blue
- RewritePath=/api-gateway(?<segment>/?.*), $\{segment}

我们如果要使用RewritePath的过滤器的话,我们可以现在断言处加一个API访问路由,在添加一个重写的路由去发访问。

我们先访问http://localhost:81/api-gateway/order/1001

SpringCloud 【Gateway-API网关】_自定义_13

在访问http://localhost:81/order/1001 发现也是可以访问的 。

SpringCloud 【Gateway-API网关】_java_14


因为这里直接走的是/product/** 这个访问路由,所以,我们再将/order/**这个访问路由去掉。再次访问。​​发现我们只能访问http://localhost:81/api-gateway/order/1001这个路由。

4.2.2 后置过滤器

1️⃣The SetStatus GatewayFilter Factory

spring:
application:
name: gateway-server
# 路由配置
cloud:
gateway:
routes:
- id: order
uri: http://localhost:8081/
predicates:
- Path=/order/**
filters:
- AddRequestParameter=info, blue
- SetStatus=201 # 默认的是200 在这里改成了201

SpringCloud 【Gateway-API网关】_gateway_15

从这里可以明显的看出,这是一个后置的过滤网关处理器。

2️⃣AddResponseHeader GatewayFilter Factory

在请求后,返回信息,添加一个Header的信息

- id: order  # 路由ID 唯一保证 与项目名保持一致即可
uri: http://localhost:8081/ # 路由地址
predicates:
# - Path=/api-gateway/**
- Path=/order/**
filters:
- AddRequestParameter=info, blue
- AddRequestHeader=X-Request-Author,

SpringCloud 【Gateway-API网关】_java_16

4.3 Gateway全局Filter GlobalFilter

全局过滤器不需要在配置文件中配置,作用在所有的路由上,我们可以用来实现很多统一化处理的业务需求,比如负载均衡,路径转发,监控,日志等等,

全局过滤器+网管过滤器=过滤器链​​ ,该过滤器链的执行顺序是根据 ​@Order注解指定的数字大小,从小到大进行排序,数字越小,优先级越高。​​

SpringCloud 【Gateway-API网关】_java_17


SpringCloud 【Gateway-API网关】_spring_18

4.4 自定义过滤器🔥🔥

SpringCloud Gateway提供过滤器的扩展功能,开发者可以根据实际的业务需求来自定义gatewayFilter网关过滤器或者GlobalFilter全局过滤器。

4.4.1 自定义Gateway过滤器

要完成自定义的网管过滤器,就先要实现GatewayFilter,Ordered接口,以及配置类
【步骤一”】编写自定义的过滤器类MyCustomerGatewayFilter

@Component
public class MyCustomerGatewayFilter implements GatewayFilter, Ordered {

@Override
public int getOrder() {
// TODO Auto-generated method stub
return -1;
}

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// TODO Auto-generated method stub
System.out.println("自定义网关过滤器...");
Mono<WebSession> session = exchange.getSession();

System.out.println(session);
return chain.filter(exchange);
}

}

【步骤二"】编写一个自定义网关过滤器的配置类,来实现之前yml的写法。比如配置path,id,uri以及将自定义的过滤器类添加进Spring的Bean容器中统一管理。

@Configuration
public class MyCustomerGatewayFilterConfig {
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder.routes().route(r->r
.path("/product/**")
.uri("http://localhost:8080/")
.filters(new MyCustomerGatewayFilter())
.id("product")
).build();
}
}

【步骤三"】去除yml里面的配置,重新启动项目,访问http://localhost:81/product/1002,发现访问成功。

SpringCloud 【Gateway-API网关】_java_19

4.4.2 自定义GlobalFilter过滤器

要自定义GlobalFilter的,首先一样也是要实现Ordered类,只不过与自定义网管过滤器不同的是,全局过滤器还需要实现​​GlobalFilter​​接口

@Component
public class MyCustomerGatewayFilter implements GatewayFilter, Ordered {

@Override
public int getOrder() {
// TODO Auto-generated method stub
return -1;
}

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// TODO Auto-generated method stub
System.out.println("自定义网关过滤器...");

return chain.filter(exchange);
}
}

发现也是没有问题的,这时候,我们观察控制台的输出:

SpringCloud 【Gateway-API网关】_自定义_20

五、Gateway网管限流

5.1 令牌桶网管限流算法

RequestRateLimiter底层实现的原理就是令牌桶算法
令牌桶内存储令牌,令牌桶需要设置令牌容量,也就是系统最大的并发量。
以一定的速率去生成令牌(具体的速率就根据系统的性能设置),放到令牌桶,如果桶满了,则丢弃;
客户端来一个请求,则先去桶里面获取令牌,拿到令牌后,则处理请求,否则直接丢弃或者返回失败。

SpringCloud 【Gateway-API网关】_自定义_21

令牌桶算法的优点:

  • 通过恒定的速率生成令牌,能够让请求处理更均匀,不会出现短时间内大量的请求处理,可以很好的控制并发;

5.2 Gateway网关限流实例

Spring Cloud Gateway官方提供了RequestRateLimiterFilterFactory过滤器工厂,使用Redis和Lua脚本实现令牌桶,来实现网关限流:
添加Redis依赖:

<!--Spring Boot Redis的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!--Letture Pool缓存连接池-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>

Yml文件配置

server:
port: 81
servlet:
context-path: /
spring:
application:
name: gateway-server
redis:
host: 192.168.188.129
port: 6379
password: null
jedis:
pool:
max-active: 100
max-idle: 100
min-idle: 100
max-wait: 60000
cloud:
gateway:
routes:
- id: product
uri: http://localhost:8080/
predicates:
- Path=/product/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 1
redis-rate-limiter.burstCapacity: 2
redis-rate-limiter.requestedTokens: 1
key-resolver: '#{@pathKeyResolver}'
- id: order
uri: http://localhost:8081/
predicates:
- Path=/order/**

🔥说明:

5.2.1 URI限流

编写一个配置类

@Configuration
public class KeyResolverConfig {

@Bean
public KeyResolver pathKeyResolver() {
/*
* return new KeyResolver() {
*
* @Override public Mono<String> resolve(ServerWebExchange exchange) { // TODO
* Auto-generated method stub return
* Mono.just(exchange.getRequest().getURI().getPath()); } };
*/
return exchange -> Mono.just(exchange.getRequest().getURI().getPath()); // URI限流
}
}

5.2.2 参数限流

@Configuration
public class KeyResolverConfig {

@Bean
public KeyResolver pathKeyResolver(){
return exchange -> Mono.just(exchange.getRequest().getQueryParams.getFirst("token")); // 参数限流
}
}

5.2.3 ip限流

/**
* 根据主机名限流
* @return
*/
@Bean
public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); // IP限流
}

然后我们访问多次http://localhost:81/product/1001地址,出现如下图的情况,说明已经实现了流量控制,我们查看redis客户端的key发现 有两个多出来的key

SpringCloud 【Gateway-API网关】_spring_22

SpringCloud 【Gateway-API网关】_自定义_23


举报

相关推荐

0 条评论