7.Gateway
8.Gateway
8.1.介绍
8.1.1.网关介绍
网关是微服务最边缘的服务,直接暴露给用户,用来做用户和微服务的桥梁

没有网关:客户端直接访问我们的微服务,会需要在客户端配置很多的ip:port,如果user-service并发比较大,则无法完成负载均衡。
有网关:客户端访问网关,网关来访问微服务,(网关可以和注册中心整合,通过服务名称找到目标的ip:prot),这样只需要使用服务名称即可访问微服务,可以实现负载均衡,可以实现token拦截,权限验证,限流等操作。
8.1.2.Gateway简介
Gateway是SpringCloud官方提供的用来取代zuul(netflix)的新一代网关组件(zuul的本质是一组过滤器,根据自定义的过滤器顺序来执行)
基于spring5.x、springboot2.x 和ProjectReactor等技术。
目地是让路由更加简单、灵活,还提供了一些强大的过滤器功能,例如:熔断、限流、重试,自义定过滤器等token校验ip黑名单等
SpringCloudGateway作为SpringCloud生态的网关,目标是替代Zuul,在SpringCloud2.0以上的版本中,没有对新版本的zuul2.0以上的最新高性能版本进行集成,仍然还是使用的zuul1.x,非Reactor模式的老版本。
为了提升网关的性能,SpringCloudGateway是基于webFlux框架实现的,webFlux框架底层则使用了高性能的Reactor模式通信框架的Netty
8.1.3.特征与功能
1.建立在SpringFramework5,ProjectReactor和SpringBoot2.0之上
2.能够匹配任何请求属性上的路由
3.谓词和过滤器特定于路由
4.Hystrix断路器集成。
5.SpringCloudDiscoveryClient集成
6.易于编写的谓词和过滤器
7.请求速率限制
8.路径改写
8.1.4.工作流程

1客户端向springcloudGateway发出请求,然后在GatewayHandlerMapping 中找到与其请求相匹配的路由,将其发送到GatewayWebHandle
Handler再通过指定的过滤器来将请求发送到我们实际的服务的业务逻辑,然后返回。
过滤器之间用虚线分开是因为过滤器可能会在发送爱丽请求之前【pre】或之后【post】执行业务 逻辑,对其进行加强或处理。
Filter在【pre】类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等
在【post】类型的过滤器中可以做响应内容、响应头的修改、日志的输出,流量监控等有着非常重要的作用。
总结:核心逻辑就是路由转发+执行过滤器链
8.1.5.三大核心概念
①Route(路由)
路由信息的组成: 由一个ID、一个目的URL、一组断言工厂、一组Filter组成。
如果路由断言为真,说明请求URL和配置路由匹配。
②Predicate(断言)
SpringCloudGateway中的断言函数输入类型是Spring5.0框架中的 ServerWebExchange。
SpringCloudGateway的断言函数允许开发者去定义匹配来自于HttpRequest 中的任何信息比如请求头和参数
③Filter(过滤)
一个标准的SpringWebFilter由servlet、listener、filter以及interceptor组成。
SpringCloudGateway中的Filter分为两种类型的 Filter
- GatewayFilter:针对某一个路由(路径)
- GlobalFilter:针对全局
8.1.6.Nginx与Gateway的区别
Nginx在做路由、负载均衡、限流之前都有修改nginx.conf的配置文件,把需要负载均衡, 路由,限流的规则加在里面。(nginx做tomcat的负载均衡)
gateway则是自动的负载均衡和路由,gateway和eureka高度集成,实现 自动的路由,和Ribbon结合,实现了负载均衡,gateway也能轻易的实现限流和权限验证。
Nginx比gateway的性能高一点。
本质区别就是:
Nginx:服务器级别的Gateway:项目级别的

8.2.快速入门
没有实现过滤功能
8.2.1.搭建login-service
①选择依赖

只选择web即可。
②修改配置文件

③添加controller类

8.2.2.搭建Gateway-server
①选择依赖

只需要选择gateway即可。
②修改配置文件

8.2.3.搭建eureka-server
8.2.4.访问测试
返回出现token即为成功。
8.3.路由
8.3.1.配置方式之代码方式

访问测试:localhost:80/path路径
8.3.2.配置方式之yml方式

8.3.3.动态路由
默认情况下Gateway会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能
需要注意的是uri的协议为lb(load Balance),表示启用Gateway的负载均衡功能。
lb://服务名称是SpringCloudGateway在微服务中自动为我们创建的负载均衡uri
例:lb://login-service
8.3.4.动态路由使用
改造刚才的例子
Gateway-server改造:


login-service改造:


访问测试:http://localhost/login-service/login
http://localhost:80/服务名称/path路径
出现token即为成功。
8.4.断言
断言就是一些布尔表达式,满足条件的返回true,不满足的返回false。
SpringCloudGateway将路由作为SpringWebFluxHandlerMapping基础架构的一部分进行匹配。
SpringCloudGateway包括许多内置的路由断言工厂。
所有这些断言都与HTTP请求的不同属性匹配。可以将多个路由断言可以组合使用SpringCloudGateway创建对象时,使用RoutePredicateFactory创建 Predicate对象,Predicate对象可以赋值给Route。
配置规则

使用
spring:
cloud:
gateway:
enabled: true #开启网关,默认是开启的
routes: #设置路由,注意是数组,可以设置多个,按照 id 做隔离
- id: user-service #路由 id,没有要求,保持唯一即可
uri: lb://provider #使用 lb 协议 微服务名称做负均衡
predicates: #断言匹配
- Path=/info/** #和服务中的路径匹配,是正则匹配的模式
- After=2020-01-20T17:42:47.789-07:00[Asia/Shanghai] #此断言匹配发生在指定日期时间之后的请求,ZonedDateTime dateTime=ZonedDateTime.now()获得
- Before=2020-06-18T21:26:26.711+08:00[Asia/Shanghai] #此断言匹配发生在指定日期时间之前的请求
-Between=2020-06-18T21:26:26.711+08:00[Asia/Shanghai],2020-06-18T21:32:26.711+08:00[Asia/Shanghai]
#此断言匹配发生在指定日期时间之间的请求
- Cookie=name,xiaobai #Cookie 路由断言工厂接受两个参数,Cookie 名称和 regexp(一个 Java 正则表达式)。此断言匹配具有给定名称且其值与正则表达式匹配的 cookie
- Header=token,123456 #头路由断言工厂接受两个参数,头名称和 regexp(一个 Java 正则表达式)。此断言与具有给定名称的头匹配,该头的值与正则表达式匹配。
- Host=**.bai*.com:* #主机路由断言工厂接受一个参数:主机名模式列表。该模式是一个 ant 样式的模式。作为分隔符。此断言匹配与模式匹配的主机头
- Method=GET,POST #方法路由断言工厂接受一个方法参数,该参数是一个或多个参数:要匹配的 HTTP 方法
- Query=username,cxs #查询路由断言工厂接受两个参数:一个必需的 param 和一个可选的 regexp(一个 Java 正则表达式)。
- RemoteAddr=192.168.1.1/24 #RemoteAddr 路由断言工厂接受一个源列表(最小大小 1),这些源是 cidr 符号(IPv4 或 IPv6)字符串,比如 192.168.1.1/24(其中 192.168.1.1 是 IP 地址,24 是子网掩码)
还有一个访问权重的设置,比如说:
80%的请求,由https://weighthigh.org 这个 url 去处理
20%的请求,由https://weightlow.org 去处理
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2
8.5.过滤
gateway的过滤器和Servlet的过滤器功能差不多,路由过滤器可以用于修改进入Http请求和返回Http响应
8.5.1.分类
生命周期分类
pre:在业务逻辑之前
post:在业务逻辑之后
种类分类
GatewayFilter需要配置某个路由才能过滤。
如果需要使用全局路由,需要配置DefaultFilters。
GlobalFilter全局过滤器,不需要配置路由,系统初始化作用到所有路由上 全局过滤器
8.5.2.自定义过滤
在上面的测试中添加一个类测试即可。

8.5.3.IP认证拦截
修改上面的自定义过滤类即可。


8.6.限流
限制一段时间内,用户访问资源的次数,减轻服务器压力。
限流分为
1.IP限流(一段时间内只能访问x次,超过则限制不让访问,过一段时间才可继续访问)
2.请求量限流(只要在一段时间内(窗口期),请求次数达到阀值,就直接拒绝后面来的访问了, 过一段时间才可以继续访问)(粒度可以细化到一个api/url,一个服务)
结合redis实现
①添加依赖
SpringCloudGateway已经内置了一个 RequestRateLimiterGatewayFilterFactory。
RequestRateLimiterGatewayFilterFactory的实现依赖于Redis,所以需要引入spring-boot-starter-data-redis-reactive这个依赖。
<!--限流要引入 Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
②添加配置
server:
port: 80
spring:
application:
name: gateway-server
cloud:
gateway:
routes:
- id: user-service-router
uri: lb://login-service
predicates:
- Path=/login
filters:
- name: RequestRateLimiter
args:
key-resolver: '#{@hostAddrKeyResolver}' #用于限流的键的解析器的Bean对象的名字。使用SpEL表达式根#{@beanName}从Spring容器中获取Bean对象
redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
redis-rate-limiter.burstCapacity: 3 #令牌桶容量
redis: #redis 的配置
host: localhost
port: 6379
database: 0
eureka:
instance:
instance-id: ${spring.application.name}:${server.port}
prefer-ip-address: true
client:
service-url:
defaultZone: http://localhost:8761/eureka
③添加config类
@Configuration
public class RequestRateLimiterConfig {
/*
* IP 限流
* 把用户的 IP 作为限流的 Key
*/
@Bean
@Primary
public KeyResolver hostAddrKeyResolver() {
return (exchange) -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
/**
* 用户 id 限流
* 把用户 ID 作为限流的 key
*/
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}
/**
* 请求接口限流
* 把请求的路径作为限流 key
*/
@Bean
public KeyResolver apiKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getPath().value());
}
}
④访问测试
快速访问多次:http://localhost/login,之后出现429错误即为成功
8.7.跨域
代码实现
@Configuration
public class CorsConfig {
@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedMethod("*");
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
}
配置文件实现
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]': // 针对哪些路径
allowCredentials: true #可以携带cookie
allowedHeaders: '*'
allowedMethods: '*'
allowedOrigins: '*

浙公网安备 33010602011771号